Server Side Swift のフレームワークVaporにおいて、Markdown文字列をHTMLに変換してくれるライブラリを使ってみます。
今回のサンプルコードはこちらのリポジトリに置いています。
各種バージョン
- Vapor Toolbox: 2.0.3
- Vapor: 2.0.5
- MarkdownProvider: 1.0.0
Vapor で MarkdownProvider
を使う
● MarkdownProviderとは?
リポジトリ:https://github.com/vapor-community/markdown-provider
- HTMLテンプレートエンジン
Leaf
にて、Markdown文字列をHTML文字列に展開してくれる#markdown()
タグを使えるようになります- Leafについてはこちら
- SwiftMarkdownパッケージのVaporProviderです
- MarkdownProviderは、SwiftMarkdownをVaporプロジェクトで簡単に使用できるようにしてくれるパッケージです
→ SwiftMarkdownパッケージ
- Markdown文字列をHTML文字列に変換してくれるライブラリです
- 実装はcmarkのSwiftラッパーです
● 基本的な使い方
Package.swiftにパッケージを追加
dependencies: [
...,
.Package(url: "https://github.com/vapor-community/markdown-provider", majorVersion: 1)
]
上記で
-
MarkdownProvider
パッケージ -
SwiftMarkdown
パッケージ
がプロジェクト内で使用可能になります。
▼ Leafに#markdown()
タグを追加する
2通りの方法でLeafのカスタムタグとして#markdown()
タグが使えるようになります。
- ProviderとしてConfig
に追加する場合
import LeafProvider
import MarkdownProvider
extension Config {
public func setup() throws {
// allow fuzzy conversions for these types
// (add your own types here)
Node.fuzzy = [JSON.self, Node.self]
try setupProviders()
}
/// Configure providers
private func setupProviders() throws {
try addProvider(LeafProvider.Provider.self)
try addProvider(MarkdownProvider.Provider.self) // <- MarkdownProviderを追加
}
}
- LeafRendererに直接追加する場合
main.swift
などで、LeafRendererに直接登録することでもmarkdown
タグが使えるようになります。
import App
import LeafProvider
import MarkdownProvider
// some code...
if let leaf = drop.view as? LeafRenderer {
leaf.stem.register(Markdown())
}
// some code...
▼ Viewテンプレート(Leaf)にマークダウンを渡す
1. ControllerからViewに渡すMarkdown文字列を設定する
import Vapor
import HTTP
final class Sample1Controller: ResourceRepresentable {
let view: ViewRenderer
init(_ view: ViewRenderer) {
self.view = view
}
/// GET /sample1
func index(_ req: Request) throws -> ResponseRepresentable {
let markdown: String = {
return "# Hello world!\n"
+ "## This is sample1.\n"
+ "This sample is to use Leaf custom tag `#markdown()`"
+ " for Simple Markdown string."
}()
return try view.make("sample1", [
"markdown": markdown
], for: req)
}
func makeResource() -> Resource<String> {
return Resource(
index: index
)
}
}
2. Viewテンプレートで#markdown()
タグを使用する
#extend("base")
#export("title") { Sample1 }
#export("content") {
#markdown(markdown)
}
#markdown(markdown)
のところでControllerから渡ってきたMarkdown文字列がHTMLにパースされる
ちなみに、#extend("base")
によって次のようなbaseテンプレートが継承されています。
この辺りはLeafの使い方になりますので、docsを参照ください。
https://docs.vapor.codes/2.0/leaf/leaf/
<!DOCTYPE html>
<html>
<head>
<title>#import("title")</title>
<link rel="stylesheet" href="/styles/app.css">
</head>
<body>
#import("content")
</body>
</html>
● Advanced
▼ HTMLタグを含むMarkdown文字列を使用する場合
Markdown文字列にHTMLタグを記述している場合、前述のような使用方法ではHTMLタグ部分はエスケープされてしまいレンダリングされません。
なので、Controller側でHTML文字列にして、Leaf側で#raw()
タグを使うことで表示させることができます。
import Vapor
import HTTP
import SwiftMarkdown
final class Sample2Controller: ResourceRepresentable {
let view: ViewRenderer
init(_ view: ViewRenderer) {
self.view = view
}
/// GET /sample2
func index(_ req: Request) throws -> ResponseRepresentable {
// HTMLタグが含まれるMarkdown文字列
let markdownString: String = {
return "# Hello world!\n"
+ "## This is sample2.\n"
+ "<p>This sample is in case of that the Markdown String contains raw HTML String.</p>\n"
+ "In this case, Leaf is ignore raw HTML String. So, you could use `markdownToHTML()` method "
+ "and put parsed HTML String to Leaf template by `#raw()`"
}()
// SwiftMarkdownパッケージの `markdownToHTML` を使ってHTMLに変換する
let markdown = try markdownToHTML(markdownString, options: [])
return try view.make("sample2", [
"markdown": markdown
], for: req)
}
func makeResource() -> Resource<String> {
return Resource(
index: index
)
}
}
↑ SwiftMarkdownパッケージの markdownToHTML
メソッドを使用することで、Markdown文字列をHTML文字列に変換することができます。
#extend("base")
#export("title") { Sample2 }
#export("content") {
#raw(markdown)
}
↑ 渡ってきたmarkdown
変数はHTML文字列になっているので、#raw()
タグを使うことでエスケープされずに表示することができます。
最後に
ちょっと雑な説明になりましたが、、こんな感じで使えます。
使う場面は限られるかもしれませんが、気軽にMarkdownをHTMLにパースできていいですね。
WebコンテンツをMarkdownで書いて、CSSにgithub-markdown-cssとかを用いれば、Markdownベースで見やすいWebコンテンツを作成できるかもしれません。
また、Vaporでの使用のみならず、SwiftMarkdownパッケージ単体で使用するだけでも十分便利なので、使い方は色々考えられるかなと思います。
あ、あと、サンプルのMarkdown文字列の英文が多少おかしいのは見逃してください