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

## 問題の概要

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

**HTMLテンプレート：**

```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>
```

**コンパイル結果：**

```html
<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](https://discuss.gohugo.io/t/lodash-template-tags-are-escaped-since-hugo-0-19/6299)

> 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](https://github.com/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](https://github.com/golang/go/issues/18569)

既に変更はマージされているため、この挙動は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`を定義する**ためだ。

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

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

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

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

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

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

`Custom Output Format`については下記のドキュメントを参照：
[Hugo - Output Formats](https://gohugo.io/extras/output-formats/)