Edited at

watchifyで変更が無い時の再バンドルをスキップする

More than 3 years have passed since last update.

watchifyを利用してる際、保存の度に変更が無くても再バンドルされるのを煩わしいと思った事は無いでしょうか?、僕はあります。

しかしwatchifyには再バンドルスキップのような機能はなく、またそのような方法も見つけられませんでした、なので利便性を考え、watchify用のプラグイン(changed-bundle)として今回作成しました。

そのプラグイン解説も兼ねてどのように対応出来たかを紹介します。

changed-bundleへのgithubリンクはこちら


使い方

インストールして

$ npm install changed-bundle

watchify実行時にこのプラグインを指定

$ watchify -v -p [changed-bundle] -o public/bundle.js src/index.js

初回はソースをハッシュ値としてキャッシュするだけなので、従来通りバンドルされます。

534086 bytes written to public/bundle.js (0.36 seconds)

2回目からは、バンドルする際にバンドルファイルの内容が前回のキャッシュと同じかをチェックし、同じ場合は再バンドルがスキップされるようになります。

*** skip write to public/bundle.js (0.01 seconds) ***

534088 bytes written to public/bundle.js (0.02 seconds)
*** skip write to public/bundle.js (0.01 seconds) ***

watchifyにもキャッシュの仕組みがありますが、導入によりファイル出力自体の処理を省けます。

頻繁にファイルを保存して不要な再バンドルが走ってディスクI/Oのボトルネックが気になったり、バンドルファイル出力のトリガ操作がある際に効果があると思います。


どういう仕組みでスキップしてるか

以下は技術的な話になります。


gulpの場合

gulp、というかgulpが内部で使用しているStream APIでファイルを出力する際は、through2モジュールによるパイプライン内にバッファ(ソースコード文字列等)があれば、最終的にgulp.destからファイルへと出力されます。

なのでgulpを使ってる際は、このパイプライン内で意図的にバッファを空にすればファイル出力をスキップ出来ます。

gulp.src('index.js')

... ここでバッファを空に出来れば出力されない ...
.pipe(gulp.dest('public'))

gulp-changed等がそのような実装になっています


watchifyコマンドの場合

骨が折れたのがこの時の実装方法です、watchifyコマンドのソース(node_modules/watchify/bin/cmd.js)を読んでも普通の方法ではスキップする手立てがなく、ハック的な手法を使う必要がありました。

パイプラインを無理やり作り変えると他のプラグインに影響が出かねないので、一端ファイル出力用のstreamがパイプラインに組み込まれるのを待った後、そのstreamをパイプラインから取り除く方法を取っています。

詳しくはソースをどうぞ。