「JSテンプレートエンジンとは?」まとめると大変だった基礎知識

こんにちは、Quidamです。

最近では社内メンバーもGitの操作にだいぶ慣れてきました。そうすると、Gitと相性の悪いツールが気になるようになって。その一つが、静的HTMLの量産に長年使ってきたDreamweaver(DW)です。DWのテンプレート機能を使えばJSテンプレートエンジンと同じようなことが出来るので、特に不便を感じることなくここまで来たのですが、テンプレートの更新で不用意に挿入される空行やスペースが、Gitで「履歴」になってしまうなど困った状態で…。

「これはマズイなー」と思っていたところで、めぐたんがNode.jsに手を出し始めたので、これはいいタイミング!と思い、DWからの卒業とJSテンプレートエンジンの社内標準化を進めることにしました。

JSテンプレートエンジンを調べると、すぐにNode.jsやExpress、GulpやGruntといった周辺ツールと合わせた使用方法の記事が見つかり、JSテンプレートエンジンそのものの正体が分かりにくかったので、まずはJSテンプレートエンジン自体を知るために、単体で動かしながら基礎を確認しました。今回はそのまとめになります。

JSテンプレートエンジンで出来ること

JSテンプレートエンジンとは「データとテンプレートを合体させ、文字列を作る仕組み」を提供するJSライブラリです。これにより、JavaScriptとHTMLを切り離して作ることができるため、マークアップやシステムへの組み込み工程を効率化することが出来ます。

マークアップの効率化

静的HTMLの量産時は、同じHTMLを繰り返し記述・修正したり、最終的にはシステムで出力されて不要になるHTMLを書くといった場面が多くとても効率が悪いのですが、JSテンプレートエンジンには(DWと同様に)次のようなテンプレート機能があるため、これらの二度手間や無駄を省くことが出来ます。

主なテンプレート機能
  • 共通部分の外部ファイル化
  • テンプレートの継承(ネスト)
  • 変数の代入
  • ifなどの条件分岐

システムへの組み込み工程の効率化

JavaScriptとHTMLを切り離して作る、ということはつまり「ロジックとデータからUIを分離する」いわゆるMV* モデルでフロントエンドを作るということなので、同じくMV* モデルで構築されたバックエンドへの組み込みがとてもスムーズになります。そうでなくても「どこがHTMLでどこがシステムによる出力なのか」や「どういった条件でHTMLが切り替わるのか」が明確になっているので、プログラマにも読みやすく組み込みがしやすいのです。

システムへの組み込み工程の効率化

大事なポイント

「要はJavaScriptなので」ということに尽きるのですが、個人的に大事なポイントだなと思ったのは次の2つです。JSテンプレートエンジンは、

  • HTMLファイルを生成するものではないこと
  • ランタイムレンダリングであるということ

HTMLファイルを生成するものではない

これは今までDWを使ってきたからこそのポイントだと思いますが、DWのテンプレート機能は結果としてHTMLファイルを生成するのに対し、JSテンプレートエンジンはHTMLファイルを生成するわけではないという点です。こうやってまとめると当たり前のことですが、JSテンプレートエンジン自体はJavaScriptのライブラリなので、実行結果としてHTMLを返す(HTMLコードを生成する)のが役割で、ファイルを作るのは役割ではない、ということですね。

なので結果としてHTMLファイルが欲しければ、GulpやGruntにファイルを生成する役割を担ってもらう必要があるのです。

ランタイムレンダリング

JSテンプレートエンジンは、JavaSctiptが実行された時にHTMLコードを生成します。実行されなければHTMLコードはありません。これは、次の章の「動かし方」で説明する2パターンのどちらでも同じで、「ページがリクエストされた時だけHTMLコードが生成・描画される」ランタイムレンダリングなんだ、という点も踏まえておく必要があると思います。

ランタイムレンダリングのイメージ

JSテンプレートエンジンの動かし方

種類によって細かくは異なると思いますが、代表的なJSテンプレートエンジンの動かし方として次の2パターンがあります。

  • HTMLにJSファイルを読み込んでブラウザ上で処理
  • Node.js上で処理

HTMLにJSファイルを読み込んでブラウザ上で処理

1つ目は分かりやすいですね。CDNが用意されているもの/いないものがありますが、jQueryのようにHTMLにJSファイルを読み込んでブラウザ上で処理を実行させる(クライアントサイド)タイプです。実行された結果はブラウザに返されるため、簡単に確認することができます。この場合実行環境にNode.jsは必要ありません。

HTMLにJSファイルを読み込んでブラウザ上で処理するイメージ

気をつけたいこと

上で書いたように、HTMLはランタイムでレンダリングされます。ただの静的ページを表示したいだけなのに、ページにアクセスする度にテンプレートを処理し、DOMを操作してコンテンツを表示するという負荷がクライアントサイドにかかるので、この方法を最終成果物(プロダクト)に採用することは推奨されていません。

JSテンプレートエンジンがそれぞれ用意している「プレコンパイル」という機能により、ランタイムの負荷は軽減されますが、それでも完全になくなるわけではありません。

Handlebars: Getting Started
Please note that this approach is not recommended for production applications. A better way is to precompile your templates. This will result in a smaller required runtime library and significant savings from not having to compile the template in the browser. This can be especially important when working with mobile devices.

ただの静的ページであれば、GulpやGruntでHTMLファイル自体を生成した方がいいですね。

Nunjucks: Getting Started
Whatever you do, make sure to precompile your templates in production! There are grunt and gulp tasks to help with that. Read more about optimal client-side configurations in Browser Usage.

Node.js上で処理

2つ目はNode.js上で実行するタイプです。実行された結果をブラウザで確認するためには、Node.jsでWebサーバを立てて、特定のURLへのアクセスでJSが実行されるようにしたりと、別で環境を用意する必要がありなかなか大変です。

これを手軽に実装する方法としてよく一緒に紹介されているのが、Node.jsのMVCフレームワークであるExpressです。Expressを使うと「なかなか大変」のところを担ってくれるので、そこを気にすることなくテンプレートエンジンを楽しむことができます。役割分担をざっくりと表現すると次のようなイメージ。

Node.js+Express+JSテンプレートエンジンの役割分担イメージ

もう一つの選択肢が、GulpやGruntなどのタスクランナーを使ってHTMLファイルを生成しそれをブラウザで確認するという方法です。「このためだけにExpressを使うのはどうなのかな…」とか「納品物としてHTMLファイルが必要」といった状況はよくあるので、結果としてこの組み合わせで使用されているケースが多いのではないでしょうか。

Node.js+Gulp+JSテンプレートエンジンの動作イメージ

この最後の方法のみ、HTMLファイルの実体を生成するためランタイムレンダリングではありません。一度ファイルが生成されればいつでもHTMLコードにアクセスできますし、開発環境にWebサーバがなくてもマークアップ作業をすることが出来ます。
フロントエンドの作業は、画像の圧縮やCSS/JSのミニファイなどタスクランナーを活用する場面が多い事を加味すると、この方法が一番しっくりきますね。

まとめ

予定よりだいぶ膨らんでしまいましたが…
JSテンプレートエンジン自体の正体と、なぜ周辺のツールが必要になるのかが整理できました。次回は、JSテンプレートエンジンの「Nunjucks」とGulpの具体的な設定例をご紹介したいと思います。

<7月26日追記>
2つ目のブログを書きました(↓)


参考)JSテンプレートエンジンの代表的なもの