Gruntタスクの設定をファイルで管理

Gruntfile.jsの大半を占めるのはタスク設定の部分だ。そこを分割してやればGruntfile/jsを小さく出来るわけで、そういうNode.jsパッケージはいくつかある。load-grunt-configsがその最も有名と思われるものだが、汎用化してあり、便利すぎ・パワフルすぎで、ちょっと仰々しすぎる気がした。もっとストレートにやっても良さそうなので、5行くらいで指定ディレクトリから設定を読み出すコードを書いて、少し使ってみた。

以下のGruntプラグインをインストールして使うGruntfile.jsを例にする。

Gruntfile.jsの書き方

grunt.file.expand()を使って.grunt/config/*.jsonをグロブし、それぞれのファイル名をキーにして、ファイルの内容を値にして設定を組み立てていく。最後にgrunt.initConfig()して読み込む。

'use strcit';

var path = require('path');

module.exports = function (grunt) {
  var config = {
    pkg: grunt.file.readJSON('package.json')
  };

  grunt.file.expand('.grunt/config/*.json').forEach(function (file) {
    config[path.basename(file, '.json')] = grunt.file.readJSON(file);
  });

  grunt.initConfig(config);

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-uglify');

  grunt.registerTask('rebuild:css', [
    'clean:css',
    'copy:css',
    'cssmin'
  ]);

  grunt.registerTask('rebuild:js', [
    'clean:js',
    'copy:js',
    'uglify'
  ]);
};

プラグイン名から設定ファイルを拾えたりすると、ロードしつつ設定の組み立てというもうちょっとスマートな実装になりそうだ。しかし実際にはプラグイン名とタスク名が一致しないことは良くあるので、それは無理がある。そうできるようにするためには設定の書き方の工夫か対応表みたいなのが必須になるだろう。

エイリアスの部分も切り離して良さそうだけど、そのエイリアスに対しての設定をまとめたりは出来ないので、切り離してもあまり意味はない。

タスク設定の書き方

タスク設定は.grunt/config/以下にtaskname.jsonという形で置く。特に何もしないのでGruntfile.jsに書く時とほぼ同じだ。ただしJSONとして読み込みパースされるので、キーと値は二重引用符で括ることと最後のカンマには気を付ける必要がある。

例えば.grunt/config/uglify.jsonは以下のようになる。

{
  "options": {
    "beautify": {
      "ascii_only": true
    },
    "preserveComments": "some"
  },
  "main": {
    "expand": true,
    "cwd": ".grunt/tmp/",
    "src": ["*.js"],
    "dest": "scripts/",
    "ext": ".min.js"
  }
}

JSONを普通に書くのは面倒なので*.coffee許容させたりすると良さそうではある。


このような形で10ほどのプラグインをインストールした状態で色々やってみたが、分割するとGruntfile.jsは短くなるものの、それが特に設定のしやすさ・わかりやすさにはつながらなかった。少なくともプラグイン単位での設定の分割は無意味と感じる。Gruntの設定の辛さは長くなって読みづらくて辛いではなくて、あるタスクの設定をあっちで書きこっちで参照しという書く辛さと、あるタスクの設定を調べる時にあっちを見てこっちを辿ってという読む辛さの組み合わせということだと結論づけた。つまりやりたいことやっていることの設定を一括して管理・参照する術がないということだ。

タスクごとまたはエイリアスごと、例えばデプロイ用の設定とかテスト用の設定とかで分割するなら、やりたいことの設定をまとめて管理でき、やっていることの設定を一気に参照できる。これなら意味がある気がするけど、そうなるとGruntに渡される引数を調べて……とか、Gruntのラッパーを作って……など、まぁまぁ大変なコードを書いてやらないと実現できないので、あまり現実的ではない。

ただ多くの人はGruntプラグインの作るタスクを直接叩くことはなく、エイリアス単位で実行するであろうし、設定の修正もエイリアス単位でまとめて行ったりするだろう。そのため、完全にエイリアス単位で管理できるようなら、挑戦する価値はありそうとも感じる。そのようなプラグインが既にあるようだが、大幅な変化が模索されている現在、そういったものに依存したら後が怖く、導入には二の足を踏む。


結局普通に書くしかないことになるわけだ。その前にタスクを使われるタイミングで絞ったりGruntの使い方を考え直したりしてGruntfile.jsが破綻しないように常に意識すると良い。回り道だけど、安全で安心な道だろう。