LoginSignup
1
2

More than 5 years have passed since last update.

HugoでEJSのテンプレートタグがエスケープされてしまう問題の解消方法

Last updated at Posted at 2017-05-18

問題の概要

Hugoをバージョン0.18から0.19にアップデートした際、それまでは問題なく出力されていたloodashテンプレートの記号<%=%>が、意図せずエスケープされてしまう問題が発生した。

HTMLテンプレート:

my-ejs-partial.html
<script type="text/template" id="js-qiita-posts-tmpl">
<% list.forEach(function (item) { %>
  <li class="qiita-tl__item">
    <a class="qiita-tl__link" href="<%= item.url %>" target="_blank">
      <span class="qiita-tl__stock" target="_blank">
        <%= item.stock_count %> <span class="qiita-tl__stock-unit">STOCKS</span>
      </span>

      <h3 class="qiita-tl__title"><%= item.title %></h3>

      <p class="qiita-tl__tags">
        <% item.tags.forEach(function (tag) { %>
        <span class="qiita-tl__tag"><%= tag.name %></span>
        <% }); %>
      </p>
    </a>
  </li>
<% }); %>
</script>

コンパイル結果:

<script type="text/template" id="js-qiita-posts-tmpl">
&lt;% list.forEach(function (item) { %>
  <li class="qiita-tl__item">
    <a class="qiita-tl__link" href="<%= item.url %>" target="_blank">
      <span class="qiita-tl__stock" target="_blank">
        &lt;%= item.stock_count %> <span class="qiita-tl__stock-unit">STOCKS</span>
      </span>

      <h3 class="qiita-tl__title">&lt;%= item.title %></h3>

      <p class="qiita-tl__tags">
        &lt;% item.tags.forEach(function (tag) { %>
        <span class="qiita-tl__tag">&lt;%= tag.name %></span>
        &lt;% }); %>
      </p>
    </a>
  </li>
&lt;% }); %>
</script>

関数を使って出力してみても直らない。

HTMLテンプレート:

{{ printf "<%= contribution %>" }}
{{ htmlUnescape "<%= contribution %>" }}
{{ htmlUnescape "&lt;%= contribution %&gt;" }}

コンパイル結果:

&lt;%!=(MISSING) contribution %!&gt;(MISSING)
&lt;%= contribution %&gt;
&lt;%= contribution %&gt;

質問してみた

仕方がないのでHugoのフォーラムで質問することにした:
Lodash template tags are escaped since Hugo 0.19 - support - Hugo Discussion

The lodash tags outside double quotes are escaped unexpectedly. I also tried these functions but the result isn't desirable. :disappointed_relieved: Currently, I haven't tried 0.20, because it hasn't appeared to Homebrew, yet.
My questions :
1. Is it a bug? or new expected behavior from 0.19?
2. Are there any solutions to keep lodash tags unescaped?

得られた回答

bepさんという、中心的な開発メンバーの方がすぐに返答してくれた。

It is probably changed behaviour in the Go version in use, you may search for it here:
https://github.com/golang/go/issues

まず、Go言語のアップデートにより、テンプレートエンジンの挙動が変わったことが原因だった。GoのIssueを見てみると、既に僕と同じ問題がバグとして報告されていた。

html/template: <script> tags with type "text/template" now escapes EJS templates · Issue #18569 · golang/go

既に変更はマージされているため、この挙動はGo1.9以降で解消されるだろう。

では、今現在はどうすれば良いのか?

This escaping of HTML templates in Go's HTML templates are mostly security motivated -- which may not be an issue when you control the input yourself. In Hugo >= 0.20 you can switch to using Go's text template package per output format by defining isPlainText=true.

Hugoのバージョン0.20以降に追加された新しいオプションによって、エスケープの挙動を変えられるようになったとのことだ。これを設定すれば、Goのアップデートを待たずに問題を解消できる。

Hugo 0.20 での解消方法

まず、問題のEJSタグが含まれるファイルのパーシャルの拡張子を.ejsに変更する。これは、Hugoの新しい仕様であるCustom Output Formatを使い、拡張子がejsのファイルには通常と違うoutputFormatを定義するためだ。

mediaTypeoutputFormatの追加はconfig.tomlへ以下を追記することによって行う。

config.toml
[mediaTypes."text/template"]
suffix = "ejs"

[outputFormats.EJS]
mediaType = "text/template"
isHTML = true
isPlainText = true

最後に、パーシャルの読み込み時にsafeHTMLフィルターを適用する。これがないとうまくいかない。

  {{ (partial "my-ejs-partial.ejs" .) | safeHTML }}

これによって問題を解決できた。

Custom Output Formatについては下記のドキュメントを参照:
Hugo - Output Formats

1
2
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
1
2