HugoのMarkdown Render Hooksで画像の出力をカスタマイズする

HugoのMarkdown Render Hooksで画像を表示するマークダウン記法のHTMLへのレンダリング処理をカスタマイズしてloading属性をつけた<img>タグを出力するようにしました。

Markdown Render Hooksとは

Markdown Render HooksはマークダウンのHTMLへのレンダリング処理をカスタマイズすることができる機能でGoldmarkを使用している場合に利用することができます。

この記事を作成している時点のバージョン(v0.88.1)では、リンク、画像、見出し、コードブロックのマークダウン記法に対応しています。

デフォルトのレンダリング処理をカスタマイズするにはマークダウン記法ごとにそれぞれ以下のファイルを作成します。

機能ファイル名
リンクlayouts/_default/_markup/render-link.html
画像layouts/_default/_markup/render-image.html
見出しlayouts/_default/_markup/render-heading.html
コードブロックlayouts/_default/_markup/render-codeblock.html

詳細はMarkdown Render Hooks | Hugoを参照ください。

画像の出力のカスタマイズ

今回は画像を表示するマークダウン記法のデフォルトのレンダリング処理をカスタマイズするのでlayouts/_default/_markup/render-image.htmlを作成します。

テンプレートに渡されるパラメータの確認

まずはMarkdown Render Hooks | Hugoに記載してあるパラメータを確認するために以下の内容でテンプレートを作成しました。

layouts/_default/_markup/render-image.html
<pre>
  .Page       |{{ .Page }}
  .Destination|{{ .Destination | safeHTML }}
  .Title      |{{ .Title | safeHTML }}
  .Text       |{{ .Text | safeHTML }}
  .PlainText  |{{ .PlainText | safeHTML }}
</pre>

テンプレートを作成したら画像を表示するマークダウン記法を書いてレンダリングされた内容からパラメータの値を確認してみます。

![<画像のテキスト"](画像パス.jpg "画像のタイトル>")

以下のHTMLがレンダリングされました。

<pre>
  .Page       |{Page(/posts/hugo-render-image/index.md) nopPage nopPage}
  .Destination|画像パス.jpg
  .Title      |画像のタイトル>
  .Text       |&lt;画像のテキスト&quot;
  .PlainText  |<画像のテキスト"
</pre>

画像を表示するマークダウン記法とそれぞれのパラメータの対応関係は以下のようになっています。

![PlainText](Destination "Title")

またTextはPlainTextをサニタイジングした値が設定されています。

loading属性をつけた<img>タグを出力させる

それぞれのパラメータと画像のマークダウン記法の対応関係が確認できましたのでloading属性をつけた<img>タグをレンダリングするようにrender-image.htmlをカスタマイズします。

layouts/_default/_markup/render-image.html
<img src="{{- .Destination | safeURL -}}" loading="lazy"
  {{- with .Title }} title="{{ . }}"{{ end -}}
  {{- with .PlainText }} alt="{{ . }}"{{ end -}} />

先ほどと同じように画像を表示するマークダウン記法を書いてレンダリングされる<img>タグを確認してみます。

![<画像のテキスト"](画像パス.jpg "画像のタイトル>")

レンダリングされた<img>タグは以下になりました。(見やすいように改行しています)

<img src="%e7%94%bb%e5%83%8f%e3%83%91%e3%82%b9.jpg"
  loading="lazy"
  title="画像のタイトル&gt;"
  alt="&lt;画像のテキスト&#34;"/>

width属性とheight属性をつけた<img>タグを出力させる

もうすこしカスタマイズしてレンダリングされる<img>タグのwidth属性とheight属性に画像のサイズを設定するようにしてみました。

layouts/_default/_markup/render-image.html
<img src="{{- .Destination | safeURL -}}" loading="lazy"
  {{- with .Title }} title="{{ . }}"{{ end -}}
  {{- with .PlainText }} alt="{{ . }}"{{ end -}}
  {{- if not (urls.Parse .Destination).Scheme -}}
    {{- with .Page.Resources.GetMatch .Destination -}}
      {{- if eq .MediaType.SubType "svg" -}}
        {{/* SVGファイルの場合はXMLとしてパースしてheight, width属性を設定 */}}
        {{- with .Content | transform.Unmarshal -}}
          {{- with index . "-width"  -}} width="{{ . }}"{{ end -}}
          {{- with index . "-height" -}} height="{{ . }}"{{ end -}}
        {{- end -}}
      {{- else -}}
        {{- with . }} width="{{ .Width }}" height="{{ .Height }}"{{ end -}}
      {{- end -}}
    {{- else -}}
      {{- $path := path.Clean .Destination -}}
      {{- if and (not (hasPrefix $path "/"))
                 (not (hasPrefix $path "../")) -}}
        {{/* ファイルが存在しない場合はエラー */}}
        {{- errorf "Not Found Image: %s in page %s" .Destination .Page.Path -}}
      {{- end -}}
    {{- end -}}
  {{- end }} />

指定された画像ファイルがページのリソースの場合、その画像のサイズを取得してwidth属性とheight属性に設定します。

<img src="%e7%94%bb%e5%83%8f%e3%83%91%e3%82%b9.jpg"
  loading="lazy"
  title="画像のタイトル&gt;"
  alt="&lt;画像のテキスト&#34;"
  width="1000" height="371" />

画像ファイルが存在しない場合はエラーにするようにしました。ただし画像ファイルのURLがスキーマを含む形式で指定されている場合はエラーとせずにwidth属性とheight属性を設定しないようにしています。

実際の画像の出力
<画像のテキスト"

まとめ

Markdown Render Hooksを利用することで、通常のマークダウン記法で書くだけでレンダリングされるHTMLをカスタマイズすることができます。

さらに他のマークダウン記法でも利用できるようになることに期待です。