grunt-este-watchでjadeを効率よくコンパイルする

[grunt-este-watch](https://github.com/steida/grunt-este-watch)を使い、インクルードされているjadeファイルや、データを記述したjsonファイル等を更新した際に、マスターとなるjadeファイルがコンパイルされるようにしてみました。

##コンパイル設定ファイルの用意

(a)コンパイル先のパス、(b)コンパイルするマスターファイル、(c)マスターファイル内で使用されているファイル（インクルードファイルや、テンプレートで使う変数を記載しているデータファイル等）を設定します。

(c)については、ファイルを逐一記載してもよいのですが、Gruntのタスク設定等で使用する[globパターン](https://github.com/isaacs/node-glob)を使えるようにしました。

この例では、src/jade/page_a.jadeを更新すると、src/jade/page_a.jadeがコンパイルされ、src/jade/_partial/**/common/配下にあるいずれかのjadeファイルや、src/jade/data/app.jsonを更新すると、src/jade/page_a.jadeとsrc/jade/page_b.jadeの2つがコンパイルされます。


```json:compilation_config.json
{
	"jade": {
	
		// (a)コンパイル先のパス1
		"src/page_a.html": {	
			"compileFile": "src/jade/page_a.jade",  // (b)コンパイルするマスターファイル1
			
			// (c)以下のファイルが更新されるとマスターファイル1をコンパイルします
			"src": [
				"src/jade/page_a.jade",
				"src/jade/_partial/**/common/*.jade",
				"src/jade/data/app.json"
			]
		},
		
		// (a)コンパイル先のパス2
		"src/page_b.html": {
			"compileFile": "src/jade/page_b.jade",  // (b)コンパイルするマスターファイル2
			
			// (c)以下のファイルが更新されるとマスターファイル2をコンパイルします
			"src": [
				"src/jade/page_b.jade",
				"src/jade/_partial/**/common/*.jade",
				"src/jade/data/app.json"
			]
		}
	}
}
```

##Gruntfile.jsの設定
esteWatchで更新ファイルを取得します。createCompilationTaskという関数は、更新されたファイルが上記コンパイル設定リストの(c)のいずれかと一致するかを確認し、一致した場合は、コンパイルするファイルとその出力先を設定した新しいタスク設定オブジェクトを返します。最後にこのタスクオブジェクトをesteWatchでjadeタスクを上書きします。

```js:Gruntfile.js
module.exports = function(grunt) {

		// globパターンでもマッチングができるようにします
		var glob = require('glob');

		// 上記コンパイル設定ファイルを読み込む
		var pages = grunt.file.readJSON('compilation_config.json');

		/**
		 * コンパイルするマスターファイルと、コンパイル先を設定したタスク設定オブジェクトを返します。
		 * 
		 * @param taskName:String			実行するタスクの名前 ex.) "jade:dev"
		 * @param updateFilepath:String		アップデートされたファイルのパス
		 * @param complieConfig: Object		コンパイル構成（compilation_config.jsonにて設定）
		 * @param options: Object			タスクオプション
		 */
		var createCompilationTask = function(taskName, updaetFilepath, complieConfig, options) {
			var needCompile,
				taskConfig = {
					options: options,
					files: {}
				};

			for (var pageDest in complieConfig) {
				var page = complieConfig[pageDest],
					srcList = page.src;

				for (var i = 0, len = srcList.length; i < len; i++) {
					var src = srcList[i],
						files = glob.sync(src);  // globパターンによるファイルリストの取得
					
					// 更新されたファイルがファイルリストのどれかに一致しているか確認
					for (var j = 0, fileLen = files.length; j < fileLen; j++) {
						// 一致した場合、jadeタスクのfilesを設定
						if (updaetFilepath === files[j]) {
							needCompile = true;
							taskConfig.files[pageDest] = page.compileFile;
							break;
						}
					}
				}
			}

			if (needCompile) {
				grunt.config(taskName.split(':'), taskConfig);
				return [taskName];
			}
		};

		grunt.initConfig({
				esteWatch: {
					options: {
						livereload: {
							enabled: false
						},
						dirs: [
							'src/jade/**/'
						]
					},
					"*": function(filepath) {
						switch (true) {
							// jadeディレクトリ内のファイルが更新されたか
							case (filepath.indexOf('src/jade') != -1):
								var options = {
									pretty: true,
									data: grunt.file.readJSON('src/jade/data/app.json')
								};
								return createCompilationTask('jade:dev', filepath, pages.jade, options);
								break;
							default:
								//
						}
					}
				},

				jade: {
						options: {
							pretty: true,
							data: grunt.file.readJSON('src/jade/data/app.json')
						},
						all: {
								files: [{
									expand: true,
									cwd: 'src/jade',
									src: ['**/*.jade', '!**/_partial/**/*.jade'],
									dest: 'src/',
									ext: '.html'
								}]
						}
				},

		});

		grunt.loadNpmTasks('grunt-este-watch');
		grunt.loadNpmTasks('grunt-contrib-jade');
		grunt.registerTask('default', ['esteWatch']);

};

```

##サンプルファイル
[こちら](https://github.com/megurock/grunt-este-watch_sample)に用意しました。

##SASSへの応用
今回はjadeのコンパイルを扱いましたが、同様のやり方でSASSのパーシャルファイルを更新すると、それをインクルードしているマスターファイルをコンパイルさせることも可能です。