必要なタスクだけを読み込むようにしてGruntタスクの実行速度を改善するというテクニックはすごく良い。けど、このようにタスクを使う側が運用でカバーするよりも、本来ならタスクを書く側が高速にタスクがロードされるようにする必要があるはず。Qiitaの記事が参照しているIssueでも似たようなことが推奨されている。

それぞれのタスクのロード時間は、そのタスクが利用しているNodeパッケージのロードにその多くが費やされている。つまり改善すべきはタスクが依存パッケージをrequire()するタイミング。Node.jsではNodeパッケージを読み込むrequire()は、自身が呼ばれたスコープでインスタンス化する(昔どこかで読んだ気がするけど見つからなかった)ので、タスクの実行まで呼ばれないスコープでrequire()すると改善する。

module.exports = function (grunt) {
  grunt.registerMultiTask('example', 'Grunt multi task example.', function () {
    // Loading Node packages inside taskFunction
    var _ = require('lodash');
    var async = require('async');
    var foo = require('foo');
    var bar = require('./bar.js');

    // Do whatever you want.
  });
};

こういう形でgrunt.registerMultiTask()の第三引数であるタスク関数内で呼ぶなら、タスクのロード時間に影響を与えない。普通にrequire()せずにプロクシー的な関数を噛ませた方が良いかもしれないが、そこまでのこともないような気がする。仮に全てのタスクがこのように書かれていたなら、それらを全部ロードしたとしても目に見えるほどロード時間は落ちないはず。同じタスクを複数回呼ぶようなタスクの場合、タスクの実行時間に無駄ができるけど、それはマイナーなケースだと思う。

JavaScript的にはアンチ・パターン?


Grunt v5.0ではgrunt.util.asyncgrunt.async._などが削除されることになっており、それぞれのタスクで個別に依存パッケージをロードしなくてはならなくなる。そのこともあって今後はタスクでパッケージを読み込む機会も増えるし、それを見据えた効率的なタスクの書き方みたいなのも考えた方が良さそう。そうでないと魅力的で高速な対抗勢力に勝てるのはプラグインの豊富さで優っている今だけなどということになりそう。