LoginSignup
4
5

More than 5 years have passed since last update.

【Server Side Swift】MarkdownProviderを使う【Vapor】

Posted at

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()タグを使えるようになります
  • 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に追加する場合

Sources/App/Config+Setup.swift
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タグが使えるようになります。

main.swift
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文字列を設定する

Sources/App/Controllers/Sample1.swift
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()タグを使用する

Resources/Views/sample1.leaf
#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/

Resources/Views/base.leaf
<!DOCTYPE html>
<html>
<head>
    <title>#import("title")</title>
    <link rel="stylesheet" href="/styles/app.css">
</head>
<body>

#import("content")

</body>
</html>

スクリーンショット 2017-06-18 12.57.59.png

● Advanced

▼ HTMLタグを含むMarkdown文字列を使用する場合

Markdown文字列にHTMLタグを記述している場合、前述のような使用方法ではHTMLタグ部分はエスケープされてしまいレンダリングされません。
なので、Controller側でHTML文字列にして、Leaf側で#raw()タグを使うことで表示させることができます。

Sources/App/Controllers/Sample2.swift
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文字列に変換することができます。

Resources/Views/sample1.leaf
#extend("base")

#export("title") { Sample2 }

#export("content") {
    #raw(markdown)
}

↑ 渡ってきたmarkdown変数はHTML文字列になっているので、#raw()タグを使うことでエスケープされずに表示することができます。

スクリーンショット 2017-06-18 12.58.11.png

最後に

ちょっと雑な説明になりましたが、、こんな感じで使えます。

使う場面は限られるかもしれませんが、気軽にMarkdownをHTMLにパースできていいですね。
WebコンテンツをMarkdownで書いて、CSSにgithub-markdown-cssとかを用いれば、Markdownベースで見やすいWebコンテンツを作成できるかもしれません。
また、Vaporでの使用のみならず、SwiftMarkdownパッケージ単体で使用するだけでも十分便利なので、使い方は色々考えられるかなと思います。

あ、あと、サンプルのMarkdown文字列の英文が多少おかしいのは見逃してください:joy:

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5