Hugo 0.55 リリースでまた後方互換性が壊れた

Shortcode の仕様変更

Hugo 0.45 のときは組み込み shortcode である ref/relref の仕様変更だったが,今回は shortcode そのものの仕様が変更になった。

Shortcodes using the {{% %}} as the outer-most delimiter will now be fully rendered when sent to the content renderer (e.g. Blackfriday for Markdown), meaning they can be part of the generated table of contents, footnotes, etc.
via Hugo 0.55.0: The early Easter Egg Edition!

具体的な例を挙げたほうが分かりやすいだろう。

たとえば記述内容を <div> 要素で囲むだけの簡単な shortcodediv-box” を作ってみる。 コードはこんな感じ。

<div class="box">{{ .Inner }}</div>

この div-box を使って

{{< div-box >}}**Hello world!**{{< /div-box >}}

と書けば .Inner 変数の内容がそのまま展開されて

<div class="box">**Hello world!**</div>

となる。 ここで

{{% div-box %}}**Hello world!**{{% /div-box %}}

と書き換えると,以前のバージョンでは

<div class="box"><strong>Hello world!</strong></div>

のように .Inner 変数の内容が markdown の文法に従って変換されていたのが, 0.55 からは {{< >}} と同じように

<div class="box">**Hello world!**</div>

と素通ししてしまうのだ。 もし markdown として処理したければ shortcode 側で

<div class="box">{{ .Inner | markdownify }}</div>

.Inner 変数の内容を markdownify 関数に渡して明示的に変換する必要がある1

なんでこんなことになったかというと {{% %}} での処理は地の記述と連動しているらしい。 たとえば span という名前で以下の内容の shortcode をつくり

<span>{{ .Inner }}</span>

これを markdown の表の中で使うと

| 強調したい |
| ---------- |
| {{< span >}}**強調**{{< /span >}} |
| {{% span %}}**強調**{{% /span %}} |
強調したい
**強調**
強調

という感じに {{< >}}{{% %}} で違いが生じる。

Hugo のテンプレート処理は文脈依存になっていて,同じ記述でもどの要素の中で書かれるか(<head> 要素か <body> 要素か,あるいは JavaScript か CSS か)で出力が違ったりする。 おそらく shortcode{{% %}} 記述でも同じように文脈依存で出力が変わるようにしたかったのだろう。

でも,私は .Inner 変数の展開を {{< >}}{{% %}} かで使い分けていたので,今回のアップデートで大ダメージを食らってしまったですよ。 しょうがないので shortcode を設計し直したけどね orz

今後の shortcode の運用方針は以下のような感じだろうか。

  • .Inner の内容を markdown ドキュメントとして処理するかどうか明示的に制御する場合は {{< >}} を使う
  • .Inner の処理を文脈依存で行う(shortcode を入れ子にするなどの)場合は {{% %}} を使う

後方互換性が壊れる変更は,少なくとも最初はオプトアウトではなくオプトインで組み込めるようにして欲しい。

Shortcode の入れ子ができてる

今回いろいろ弄っていて気がついたのだが,いつの間にか shortcode の入れ子ができるようになってたんだね。 いつのバージョンからだろう。

たとえば

{{% div-box %}}{{% ruby "Hello world!" %}}こんにちは世界{{% /ruby %}}{{% /div-box %}}

と書くと

<div class="box"><ruby><rb>こんにちは世界</rb><rp> (</rp><rt>Hello world!</rt><rp>) </rp></ruby></div>
こんにちは世界 (Hello world!)

などとできるようになっていた。 入れ子記述は {{< >}} でも {{% %}} でもできる。 {{< >}}{{% %}} 混在でもOK。

ちなみに ruby は自作の shortcode で中身はこんな感じ。

<ruby><rb>{{ .Inner }}</rb><rp> (</rp><rt>{{ index .Params 0 }}</rt><rp>) </rp></ruby>

特に権利は主張しないので(するほどの内容じゃないし)自由に使ってください。

Deprecated な変数・関数

Hugo 0.55 を起動すると以下のワーニングが出るようになった。

$ hugo
WARN 2019/04/13 09:00:00 Page's .Hugo is deprecated and will be removed in a future release. Use the global hugo function.
WARN 2019/04/13 09:00:00 Page's .RSSLink is deprecated and will be removed in a future release. Use the Output Format's link, e.g. something like:
    {{ with .OutputFormats.Get "RSS" }}{{ .RelPermalink }}{{ end }}.
WARN 2019/04/13 09:00:00 Page's .GetParam is deprecated and will be removed in a future release. Use .Param or .Params.myParam.

テンプレート内で .Hugo, .RSSLink 変数および .GetParam 関数が使われていると上記ワーニングが出る。

.Hugo の廃止と代替手段

(以前の内容を書き換えた)

.Hugo 変数は将来バージョンで削除されるようだ。 代替として(変数ではなく) hugo 関数が用意されている(Thanx @peaceiris)。 出力例は以下の通り。

テンプレート 出力内容
{{ hugo.Generator }} <meta name="generator" content="Hugo 0.55.6" />
{{ hugo.Version }} 0.55.6
{{ hugo.CommitHash }} a5d4c82d
{{ hugo.BuildDate }} 2019-05-18T07:56:30Z
{{ hugo.Environment }} production

この手が使えるなら .Site 変数も関数で用意してほしいものである。

.RSSLink の廃止と代替手段

.RSSLink 変数も将来バージョンで削除されるようだ。 代替として .AlternativeOutputFormats および .OutputFormats 変数が使える。 たとえば <head> 要素内なら

{{ with .Site.Home.AlternativeOutputFormats.Get "RSS" }}
  <link rel="alternate" href="{{ .Permalink }}" type="application/rss+xml" title="{{ $.Site.Title | plainify }}">
{{ end }}

と書けばいいし <head> 要素以外なら

{{ with .OutputFormats.Get "RSS" }}
  <a href='{{ .RelPermalink }}' title='Feed'>Feed</a>
{{ end }}

などと書ける。 .AlternativeOutputFormats および .OutputFormats 変数はかなり応用範囲が広くて,たとえば私はフィードを JSON 形式でも用意しているが,

{{ with .Site.Home.AlternativeOutputFormats.Get "JSON" }}
  <link rel="alternate" href="{{ .Permalink }}" type="application/json" title="{{ $.Site.Title | plainify }}">
{{ end }}

と書けば簡単に <head> 要素に組み込める。

.GetParam の廃止と代替手段

.GetParam 関数については随分前からアナウンスがあったので使っている人はいないと思うが .Param 関数で代替できる。

ブックマーク


  1. もうひとつの方法としてはテンプレート・ファイルの先頭で {{ $_hugo_config := `{ "version": 1 }` }} と呪文を唱えることで 0.55 以前の動作に戻る。が,これ将来バージョンで無効になるよなぁ,多分。 [return]