Grunt で変更のあったファイルだけを処理する
僕のやり方が悪いのかもしれないけど、Gruntでファイルを watch して変更があったら任意のタスクを走らせるとき、関係ないファイルの分まで処理される。たとえば grunt-contrib-jshint とか、変更のあったファイル以外もチェックするのは意味がないし無駄な時間がかかるのでイライラする。そういうくだらないことで心の安寧を乱されたくないときの方法です。
概要
- 実行したいタスクを引数の取れるタスクでラッピングする
- 引数に応じてタスクの設定を変更して実行する
サンプル
説明
サンプルでは CoffeeScript をコンパイルするタスクがあって、Gruntfile.coffee では以下のようなカスタムタスクを設定している。→ 参照
grunt.registerTask( 'coffee' 'Compile CoffeeScript files into JavaScript' -> grunt.task.run "-coffee:#{toTaskArgs(arguments)}" )
ここの toTaskArgs というのは与えられた引数を :
で結合する関数。Grunt ではタスク名に続けて :引数
をつけることができるので、それを受け取って -coffee
というプライベートタスクに渡している。(プライベートタスクというのは適当につけた名称)
で、この -coffee
というのが 実行したいタスクを引数の取れるタスクでラッピングした タスクで、この中で 引数に応じて grunt-contrib-coffee
の設定を変更して実行する。 → 参照
grunt.registerTask '-coffee', (filter)-> src = grunt.file.expand 'src/**/*.coffee' # 対象の全ファイル src = filterFiles src, filter # filter にマッチするものだけを残す return if src.length is 0 # マッチするものがなければ終了 # 初回のときだけ loadNpmTasks 'grunt-contrib-coffee' する loadNpmTasksIfNeeded 'grunt-contrib-coffee' # coffee タスクの設定をして grunt.config.data.coffee = files: expand: yes cwd : 'src/' src : _.map(src, (path)-> _.rest(path.split('/')).join '/') dest: 'lib/' ext : '.js' # タスクを呼び出す grunt.task.run 'coffee';
ここの filterFiles というのは配列要素からフィルタ文字列に一致するものだけを抽出する関数(フィルタがなければ全部通す)で、 loadNpmTasksIfNeeded というのは最初の一回だけ loadNpmTasks
する関数です。
こういう設定で grunt coffee:file1
したときは file1.coffee
とか file100.coffee
とか file1/*.coffee
だけを対象に、引数を省略して grunt coffee
したときは、フィルタが無効になり file1.coffee
も file2.coffee
も全部の CoffeeScript を対象にタスクを走らせることができる。ターミナルがちょっと残念な感じになるけど
Running "coffee:file" (coffee) task # 最初に設定したカスタムタスク Running "-coffee:file" (-coffee) task # カスタムタスクから呼ばれるプライベートタスク Running "coffee:files" (coffee) task # grunt-contrib-coffee のタスク
で、変更があったファイルだけを処理したい場合は watch
タスクから引数つきでプライベートタスクを呼ぶようにすれば良い。僕は este-watcher なのでこんな感じ。 → 参照
grunt.registerTask '-watch', -> loadNpmTasksIfNeeded 'grunt-este-watch' grunt.config.data.esteWatch = options: dirs: 'src/**/' coffee: (file)-> "-coffee:#{file}" grunt.task.run 'esteWatch'
一応注意すべき点は、watch
タスクから呼ぶのはプライベートタスク(-で始めている方)でないといけない。なぜなら最初に設定した coffee
タスクは -coffee
タスク内で上書きされてしまうので 2回目以降は引数を取れなくなってしまう。
あとは grunt --help
したときにプライベートタスクが表示されると鬱陶しいのでガードしたりとかすると親切。→ 参照
実際に使っている様はこんな感じです。このプロジェクトでは CoffeeScript は使っていないけど、lint とかタイポチェックとかテストやカバレッジとか数種類のタスクをターゲットを絞って実行している。ごちゃごちゃしているので閲覧注意です。