gulpで手軽にEJSテンプレートをHTMLに変換

[gulp](http://gulpjs.com/)を使って[EJS](http://www.embeddedjs.com/)テンプレートをHTMLに書き出す方法を試してみたので、その導入手順などをまとめてみました。

<br>

## EJSについて
* HTMLを生成するテンプレートエンジンのひとつ
* Node.js環境で動作し、テンプレートタグ中の処理はJavaScriptで記述できる
* **HTMLにテンプレートタグを埋め込む形なので学習コストが低い**<br>
　→　PHPみたいな事をJavaScriptでやるイメージ
* Webサーバ上で動的ページとして出力する使い方を想定しているっぽい
* けど、ローカル環境で静的ページとしての出力も可能（gulp/Gruntなどと連携すると簡単そう）

よく比較に挙げられている[Jade](http://jade-lang.com/)の場合はRubyのテンプレートエンジンHamlに影響を受けているらしく、テンプレートタグ以外のHTMLの記述も通常とは異なります（いわゆる短縮文法）。
Jadeの方がコードの記述量は抑えられて便利そうですが、学習コストがそれなりにあるので今回は簡単に導入できそうなEJSの方を試してみました。

<br>

## やる事

今回はローカル環境のgulp+EJSを利用して、

1. EJSテンプレート中に変数タグを埋め込み
1. JSONファイルで別途データを定義
1. テンプレート中の変数タグをJSONデータで置換してHTMLを生成

の処理をJSテンプレートかJSONファイルが更新されたら自動的に実行します。

<br>

## EJSテンプレートに変数タグを埋め込み
gulp+EJSの環境構築は後で説明するとして、先に使用するEJSテンプレートのソースコードを紹介します。

```html+erb:index.ejs
<!DOCTYPE html>
<html lang="ja">
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">

	<meta charset="UTF-8">
	<title><%= pageTitle %> - <%= siteName %></title>

	<meta property="og:type" content="website">
	<meta property="og:locale" content="ja_JP">

	<meta property="og:site_name" content="<%= siteName %>">
	<meta property="og:title" content="<%= pageTitle %>">
	<meta property="og:description" content="これは<%= pageTitle %>のサンプルです。">
	<meta property="og:url" content="<%= siteRootURL %>index.html">
	<meta property="og:image" content="<%= siteRootURL %>images/facebook.png">

	<meta property="fb:app_id" content="<%= facebookAppID %>">

</head>

<body>
	<h1><%= pageTitle %></h1>
	<p>これは<%= pageTitle %>のサンプルです。</p>
</body>
</html>
```

ソースコード中の`<%= 変数名 %>`の記述箇所が変数タグになります。
それ以外は通常のHTMLそのままです。

今回使っている変数タグは以下の通りです。

| 変数名 | 内容 |
|:--------------|:------------------|
| siteName      | サイトの名前       |
| pageTitle     | ページのタイトル   |
| siteRootURL   | サイトのルートURL  |
| facebookAppID | FacebookのアプリID |

<br>

### 2種類の変数タグ
EJSでは変数タグは`<%= 変数名 %>`あるいは`<%- 変数名 %>`で記述します。
**両者の違いはHTML特殊文字をエスケープするかどうか**になります。

今回のサンプルでは全てエスケープ処理を行う`<%= 変数名 %>`の方を使っています。

<br>

## JSONファイルでデータを定義
テンプレート側の準備が済んだので、次に当て込むデータをJSONファイルで用意します。
先ほどの変数タグに対応するキー名を使用してJSONオブジェクトでデータを定義します。

```json:index.json
{
	"siteName": "EJS & gulpサンプルサイト",
	"pageTitle": "トップページ",
	"siteRootURL": "http://www.exsample.com/sample/",
	"facebookAppID": "1234567890"
}
```

`siteName`の箇所でHTML特殊文字「&」を使用していますので、これはHTML出力時にはエスケープされて出力されます。

<br>

## gulp用のEJSのインストール

ここからはgulp+EJSの環境構築の手順になります。
といっても、**gulpの作業ディレクトリにgulp-ejsのパッケージをインストールするだけ**です。

```sh
npm install --save-dev gulp-ejs
```

これでgulpでEJSの処理が出来るようになります。
めちゃくちゃ簡単ですね。

<br>

## gulpタスクの定義
今回は`index.ejs`と`index.json`の両方を監視して、変更があったら`index.html`を出力するタスクを定義したいと思います。
説明を簡略化するために、全てのファイルはgulpの作業ディレクトリに置くものとします。

```js:gulpfile.js

// JSONファイルの読み込みに使用
var fs = require('fs');
// gulp本体
var gulp = require('gulp');
// エラーハンドリング
var plumber = require('gulp-plumber');
// ファイル名変更
var rename = require('gulp-rename');
// EJS本体
var ejs = require("gulp-ejs");

// タスク定義
gulp.task('watch', function (callback) {
	// index.ejsとindex.jsonの両方を監視
	gulp.watch(['./index.ejs', './index.json'], function (e) {
		// 削除以外 == 追加 or 変更
		if (e.type != "deleted") {
			// 最新のJSONファイルを同期読み込みしてオブジェクトを生成
			var json = JSON.parse(fs.readFileSync("./index.json"));

			gulp.src("./index.ejs")
				.pipe(plumber())
				// オブジェクトを渡してデータの当て込み
				.pipe(ejs(json))
				// index.htmlに名前を変更
				.pipe(rename("index.html"))
				.pipe(gulp.dest("./"))
		}
	});
});
```

`index.ejs`と`index.json`のどちらかのファイルが追加あるいは変更された時に処理が走るようになっています。

まず最初にJSONファイルを読み込んでオブジェクトを生成します。
Node.jsのfsモジュールを使えば同期処理が簡単にできて良いですね。

その後、ejsモジュールにオブジェクトを渡し、それを`index.ejs`のストリームに渡せばHTMLファイルに変換してくれます。

<br>

## gulpタスクの起動
いつも通り、gulpコマンドにタスク名を渡してタスクを起動します。

```sh
gulp watch
```

<br>

## gulpタスクの実行結果

監視に成功して処理が実行されると、下記の`index.html`が自動的に生成されます。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">

	<meta charset="UTF-8">
	<title>トップページ - EJS &amp; gulpサンプルサイト</title>

	<meta property="og:type" content="website">
	<meta property="og:locale" content="ja_JP">

	<meta property="og:site_name" content="EJS &amp; gulpサンプルサイト">
	<meta property="og:title" content="トップページ">
	<meta property="og:description" content="これはトップページのサンプルです。">
	<meta property="og:url" content="http://www.exsample.com/sample/index.html">
	<meta property="og:image" content="http://www.exsample.com/sample/images/facebook.png">

	<meta property="fb:app_id" content="1234567890">

</head>

<body>
	<h1>トップページ</h1>
	<p>これはトップページのサンプルです。</p>
</body>
</html>
```

変数タグが使われていた箇所がJSONで定義した値に変換されているのが確認できるかと思います。
特殊文字`&`の箇所もちゃんとエスケープされていますね。

今回は一番簡単な変数タグのみを使う方法を試してみましたが、他にもJavaScriptの処理を書くタグ(`<% 処理 %>`の形式)も用意されていますので、この辺りは今後試してみたいと思います。