Skip to content

Why Mustache not Nimja

Kazuya Takei edited this page Oct 6, 2026 · 1 revision

テンプレートエンジンに nimja ではなく mustache を採用した背景

2026-10-06 時点で整理した内容です。 採用当時の判断はコミットログ・Issue に明記されていないため、仕様と age の使い方から考えた事後の考察です。

結論

nimja はテンプレートをコンパイル時に Nim のコードへ変換する設計です。そのため、age の中心機能である「ユーザーが設定ファイルに書いたテンプレートを実行時に展開する」用途では使えません。比較するまでもなく、候補から外れた可能性が高いと考えています。

履歴で確認できたこと

  1. mustache は Rust から Nim へ移行していた時期に、01ff06c feat: Register updating engine(2025-04-29)で導入されました。コミット本文はありません。
  2. Rust 版では Jinja2 系の Tera を使っていました。
  3. #13 には「Jinja2/Tera 形式の {% for _ in new_version %}={% endfor %} が mustache 移行で動かなくなった」とあり、sameLengthChars ラムダで対応しています。Jinja 系との互換性を失うことは認識されていたものの、その上で mustache を選んでいます。
  4. リポジトリの履歴全体に "nimja" という文字列は出てきません。

仕様の比較

観点 mustache (nim-mustache) nimja
テンプレートを処理するタイミング 実行時に文字列を解釈 コンパイル時に Nim のコードへ変換(マクロ)
テンプレートの渡し方 実行時の任意の string tmpls*(str: static string, ...)。コンパイル時に決まっている文字列だけ
値の渡し方 実行時に Context へ詰める(castValue で型を変換) Nim の変数をそのまま参照(型チェックあり)
構文 制御構文の少ない構文(Logic-less) Jinja2 / Twig 風(for, if, extends など)
テンプレートを変えたとき 再ビルド不要 再ビルドが必要(HCR は開発用に再コンパイルして読み込み直す仕組み)

age での使い方

  1. src/age/engine.nim:.age.toml の search / replace を、実行時に render(ctx) で展開しています(中心機能)。
  2. src/age/info.nim / src/age/init.nim:const で埋め込んだテンプレートを展開しています。
  3. src/age/templating.nim:now、nowFormat、sameLengthChars(ラムダ)を Context に入れています。

考察

  1. 決め手:上の 1 では、ユーザーの設定ファイルから実行時に読み込んだ文字列を展開する必要があります。nimja は static string しか受け取れないため、原理的に使えません。HCR はアプリの開発者向けの仕組みで、配布されたバイナリをユーザーが使う場面には当てはまりません。
  2. 補足(推測):Rust 版の Tera と構文が近い nimja のほうが移行は楽だったはずです。それでも互換性を捨てて mustache にしたことは、1 の制約があったと考えると自然に説明できます。
  3. 補足(推測):age のテンプレートは変数の差し込みが中心で、mustache で十分足ります。足りない部分(文字数を合わせる処理など)はラムダで補えます。
  4. nimja が使える範囲:コンパイル時に決まっている info.nim / init.nim の埋め込みテンプレートだけです。ただ、依存ライブラリが 2 つになり使い分けも生じるため、統一する利点はほとんどありません。