Hugoのテンプレートは、Goのテンプレート言語にHugoの関数とページ
オブジェクトを組み合わせたものです。ショートコードも同じ言語を使用しますが、
コンテンツ作成者はMarkdownから呼び出し、Hugoが.Contentを構築します。
Goテンプレートのコンテキストとスコープに従う #
テンプレートアクションは{{と}}の内側に記述します。パイプラインは各コマンドの
結果を次のコマンドの最後の引数に渡します。
{{ .Title | strings.TrimSpace | htmlEscape }}ドット(.)は現在のコンテキストです。with、range、テンプレート呼び出しでは
ドットを再束縛できるため、より狭いスコープに入る前に外側のオブジェクトを捕捉します。
{{ $page := . }}
{{ range .Pages }}
<a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
<span>{{ $page.Site.Title }}</span>
{{ end }}変数は$で始まり、宣言されたスコープ内で参照できます。特殊なルート変数$は
初期状態ではテンプレートに渡されたコンテキストを参照しますが、明示的に名前を付けた
変数を使うと、ネストしたコードをレビューしやすくなります。
Goテンプレート関数は、パイプラインで変換できる値を返します。関数によっては最後の
戻り値としてエラーも返し、nilではないエラーが発生するとテンプレートの実行は停止します。
任意の値にはwithを使い、値がないことがコンテンツの契約違反になる場合は、不完全な
マークアップを黙って出力するのではなくerrorfを使います。
コンテキストに応じたエスケープを維持する #
HTMLレイアウトはGoのhtml/templateを通じて実行されます。値がテキスト、属性、URL、
CSS、JavaScriptのいずれに現れるかに応じてエスケープされます。
<a href="{{ .Params.target }}">{{ .Params.label }}</a>safeHTML、safeCSS、safeJS、safeURLなどの関数は、あるコンテキストに対して
値を信頼済みとして扱います。これらは信頼できない入力をサニタイズしません。サイトで
生成または検証したコンテンツにだけ適用してください。誤ったsafe型を使うと、
クロスサイトスクリプティングの経路を作る可能性があります。
Hugoのtemplate.HTMLに類似したsafe値は、パーシャルの境界も越えます。したがって
パーシャルでは、プレーンテキスト、URL、ページオブジェクト、信頼済みマークアップの
どれを期待するかを文書化する必要があります。
パーシャルには明示的なデータを渡す #
layouts/_partials/以下のパーシャルは、再利用可能なテンプレート断片を
レンダリングします。呼び出し側がドットを選択します。
{{ partial "card.html" (dict
"page" .
"compact" true
) }}card.html内では.pageと.compactを利用できますが、元のページが暗黙的に
復元されることはありません。明示的な辞書を使うと、パーシャルが呼び出し箇所で
たまたま有効だったドットに依存することを防げます。
partialCachedはビルド中にパーシャルの結果を保存します。
{{ partialCached "menu.html" . .Language.Lang .Section }}キャッシュのバリアントには、出力を変更し得るすべての入力を含める必要があります。 バリアントキーがないと、ページ固有のコンテンツが無関係なページで再利用される可能性があります。
ショートコードのテンプレートとリソースを特定する #
現在のHugoでは、プロジェクトのショートコードテンプレートはlayouts/_shortcodes/に
配置されます。モジュールやテーマは、より低い優先順位の定義を提供できます。
サブディレクトリはショートコード名の一部になります。docs/noteの呼び出しは、次のような
テンプレートに解決されます。
layouts/_shortcodes/docs/note.html呼び出しはコンテンツページに記述します。そのページは通常のファイルでも、バンドルの
index.mdでも構いません。アセットはレイアウトディレクトリには配置しません。
リーフバンドルで使用するショートコードは、.Page.Resources.Getを通じて兄弟リソースを
解決できます。一方、サイト全体で使うアセットはグローバルリソースパイプラインから取得します。
ショートコードには、周囲のページをドットとするのではなく、ショートコードコンテキストが
渡されます。一般的なメンバーには.Page、.Params、.Get、.Inner、
.InnerDeindent、.Ordinal、.Parentがあります。名前付き引数と位置引数は、曖昧に
混在させないでください。
{{ $src := .Get "src" }}
{{ with .Page.Resources.Get $src }}
<img src="{{ .RelPermalink }}" alt="{{ $.Get "alt" }}">
{{ else }}
{{ errorf "shortcode image %q not found in %s" $src $.Page.Path }}
{{ end }}Markdownの境界を選択する #
Hugoには2種類の区切り形式があります。
{{< note >}}はショートコードテンプレートの出力を挿入しますが、その出力を Markdownレンダラーには渡しません。{{% note %}}はショートコードテンプレートの出力をMarkdownレンダリングに渡します。
ショートコードがMarkdownを生成する場合はパーセント形式が適しています。テンプレートが 最終HTMLを担当する場合は山括弧形式が適しています。Markdown形式ではインデントも重要です。 4つのスペースによって生成コンテンツがコードブロックになる可能性があるためです。 Goldmarkのunsafe-HTML設定も、Markdown経路に入る生HTMLに影響します。
ペア形式のショートコードでは、Hugoがネストしたショートコード呼び出しを解決した後の
内部コンテンツが.Innerに格納されます。ショートコードテンプレートは、その値を直接
レンダリングするか、.Page.RenderStringを通して渡すかを決定します。すでにレンダリング
された値を二重にレンダリングしないでください。
リテラルの区切り文字を安全に出力する #
ショートコードに見えるテキストは、Markdownレンダラーがフェンスを処理する前に ショートコード展開が行われるため、Markdownのコードフェンスでは保護されません。 Hugoのコメントエスケープを使うと、検索を試みずにリテラルの例を出力できます。
{{< note >}}
{{% note %}}レンダリングされたページで区切り文字を表示するだけなら、HTMLエンティティも選択肢になります。 レンダリング結果からリテラルのショートコード構文を読者がコピーできる必要がある場合は、 コメントエスケープを使います。
検索と実行の失敗を診断する #
不明なショートコードがあると、通常はコンテンツファイルとショートコード名が報告されます。 次の順序で確認します。
- 呼び出し箇所で使用している名前と大文字・小文字。
_shortcodesディレクトリと、名前に含まれるサブディレクトリ。- 有効なモジュールマウントとテーマの優先順位。
- プロジェクトのバージョンが現在のレイアウト名前空間を想定しているかどうか。
- 検索後にテンプレート実行が失敗していないか。引数またはリソースが存在しない可能性があります。
続行可能なアクション可能な診断にはwarnfを使い、ビルドを失敗させる必要がある
不変条件の破れにはerrorfを使います。テンプレートはサイト構造を提供し、
パーシャルは構造を再利用し、ショートコードは作成者が制御するコンテンツと
意図的に制限されたテンプレートAPIを橋渡しします。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)