Hugoのレンダーフックを使ったMermaidの利用

image

独自構文のテキストから、各種のダイアグラムを生成できるMermaidという便利なライブラリがありますが、現時点ではHugoでサポートされていません。

このため通常、

  • 独自のショートコードを作成する
  • 言語としてmermaidを指定したコードブロックを使用し、mermaidでlanguage-mermaidクラスの要素を変換対象として指定する

などの実装が多かったと思うのですが、公式サイトを調べていたところv0.93.0からサポートされたcodeブロックに対するレンダーフックを用いた例が載っており、よりスマートに実装できそうでした。

ここでは公式サイトのレンダーフックを用いたMermaidの組み込み方法を説明します。

レンダーフックの追加

codeブロックに対するレンダーフックを定義するには、

layouts/_default/_markup/render-codeblock-言語名.html

というファイルを作成します。今回ファイル名を、

layouts/_default/_markup/render-codeblock-mermaid.html

とすることで、

1
2
3
4
```mermaid
flowchart LR
    Start --> Stop
```

というような、言語にmermaidを指定したコードブロックに対してレンダーフックが起動します。レンダーフックの内容は以下の通りです。

render-codeblock-mermaid.html
1
2
3
4
<div class="mermaid">
  {{- .Inner | safeHTML }}
</div>
{{ .Page.Store.Set "hasMermaid" true }}
  • <div class="mermaid">でコードブロックの内容を囲む
  • Mermaidの記述があることを表すhasMermaidフラグをtrueにする

テンプレートの修正

テンプレートについては、

  • layouts/_default/baseof.html
  • layouts/_default/single.html

など、Mermaidのコンテンツを表示したいテンプレートへ以下の内容を追加します。私の場合、通常エントリでのみ表記できれば良いためsingle.htmlへ追加しました。

single.html
1
2
3
4
5
6
{{ if .Page.Store.Get "hasMermaid" }}
  <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
  <script>
    mermaid.initialize({ startOnLoad: true });
  </script>
{{ end }}

このコードはhasMermaidフラグがtrueの場合のみ、MermaidのJavascscript読み込みと初期化を行います。これにより、Mermaidの記述がないページではコードが展開されずムダな処理を抑止できるわけです。

上記処理をテンプレートへ追記する場合の注意点としては、.Contentが出現する箇所より下へ書く必要があるということです。Hugoでは.Contentが実行(評価)されるまではレンダーフックは処理されないためです。

参考サイト