Handlebars.jsを使ったファイル生成Gruntタスク

主にHTMLの生成を行うGruntタスクの話。色々なテンプレート・システムの利用を考えたんだけど、Handlebars.jsにした。よく使うからというのもあるし、いざとなったらデータの再構成を待たずにその場しのぎでテンプレートにロジックを混ぜてお茶を濁せるのが好き。その場しのぎ、お茶を濁す、良い言葉だ。

このGruntタスクは指定されたHandlebars.jsテンプレート(例えばfoo.hbs)をレンダリングするだけのもの。レンダリングに使うデータは、基本のメタデータ(metadata.jsonの中味)とテンプレート・ファイルごとに指定できるメタデータ(foo.jsonの中味)をGruntに含まれるLo-Dashextend()を使ってマージしたものを使う。Gistのサンプルにあるように基本のメタデータにないものを自由に追加できるし、基本のメタデータを上書きすることも出来る。

コアのgenerate.jsではincludeというヘルパー関数を作って共通部分を別に切り出せるようにした。ほぼSSIのインクルードと同じようなもの。Handlebars.jsが優秀なので、取り込むテンプレートでも普通にデータの利用は可能。

テンプレートと出力が1対1なシステムなので、コンテンツ部分は直接テンプレートに混ぜている。僕の場合は大体HTMLで配信するものはHTMLで書くので、Markdownで書いたコンテンツを外から取り込んで……とかそういうのを機能として作っちゃうまではやらなかった。これまたHandlebars.jsが優秀なので、別にMarkdownで書いたものをHTMLに変換してコンテンツとして取り込むなどもたぶんメタデータに関数書くだけでいける。コアでの変更はMarkdownをHTMLに変換するためのMarked等をrequire()しておくくらい。

あとはGruntの動的マッピングや柔軟なタスク構成にお任せ。サンプルのGruntfils.jsのように動的マッピングで指定ディレクトリ以下の*.hbsを一気に処理するのが基本で、指定したファイルのリビルドだけを行うのを作っておいたりとか、ウェブログの更新に伴いいくつかのファイルの更新だけを行うのを作っておいたりとか環境に合わせて色々タスク設定を作る。例えば指定したファイルのリビルドなら以下の様な設定を作ってやると良い。

generate: {
  file: {
    expand: true,
    cwd: '.grunt/html/',
    src: grunt.option('file'),
    filter: 'isFile',
    dest: './',
    ext: '.html'
  }
}

これで--fileオプションを見て生成できる。

$ grunt generate:file --file=index.hbs

面倒くさいテンプレートと出力のマッピングや、コマンド(やボタン)一発で作業を一気にこなすというようなCMSの基本的な部分をGruntによっかかっている。するとこのような数十行のJavaScriptでウェブサイトの管理……とまではいかないけど、効率的な運営くらいは可能になる。