dackdive's blog

新米webエンジニアによる技術ブログ。JavaScript(React), Salesforce, Python など

thread-loaderとcache-loaderでwebpackのビルドを高速化する

はじめに

こちらのスライドを見て。
Webpackのビルド時間を1/3にした話 #gotandajs // Speaker Deck

紹介されている thread-loader も cache-loader も知らなかった!ので、使い方やどういった効果があるのか自分でも調べてみます。

なお、スライド中にもありますが、たしかに webpack 公式ドキュメントの Build Performance でもこれらの loader について言及されていました。


thread-loader

Runs the following loaders in a worker pool.

時間のかかる(expensive)loader の処理を worker pool で実行し、それにより複数スレッドでの並列ビルドを可能にする?ようです。
(worker pool という用語はどこ由来なのかわからなかった)


使い方

thread-loader を他の loaders の一番上に指定する。

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve("src"),
        use: [
          "thread-loader",
          "expensive-loader"
        ]
      }
    ]
  }
}


オプション

色々あるみたいなので #Examples の with options の項を参照。


注意

Each worker is a separate node.js process, which has an overhead of ~600ms. There is also an overhead of inter-process communication.

Use this loader only for expensive operations!

worker は独立した Node のプロセスなので、起動のオーバーヘッドはそれなりに大きいらしい。
時間のかかる処理にだけ使うように、とのこと。


その他

prewarming

worker の起動による遅延を回避するために、事前に worker pool を起動(warmup)しておくことができる。

const threadLoader = require('thread-loader');

threadLoader.warmup({
  // pool options, like passed to loader options
  // must match loader options to boot the correct pool
}, [
  // modules to load
  // can be any module, i. e.
  'babel-loader',
  'babel-preset-es2015',
  'sass-loader',
]);


で、結局どういった loader に適用すればいいの?

具体例は挙げられてなかった。
スライドや、リポジトリexample/webpack.config.js を参考にするといいと思う。

example では babel-loader を使った js のトランスパイルと sass-loader & ExtractTextPlugin による SCSS の処理に適用していた。


cache-loader

後続の loaders の結果をディスクにキャッシュする。


使い方

thread-loader と同じく、他の loaders の先頭に指定する。

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.ext$/,
        use: [
          'cache-loader',
          ...loaders
        ],
        include: path.resolve('src')
      }
    ]
  }
}


オプション

  • cacheDirectory
    • キャッシュファイルの保存先
    • デフォルトは path.resolve('.cache-loader')
  • cacheIdentifier
    • ??? "Provide an invalidation identifier which is used to generate the hashes. You can use it for extra dependencies of loaders."
    • デフォルトは cache-loader:{version} {process.env.NODE_ENV}{version} は cache-loader のバージョン?)


注意

キャッシュファイルの読み書きというオーバーヘッドが発生するので、こちらも適用は expensive loaders だけに留めるように、とのこと。

また https://webpack.js.org/guides/build-performance/#persistent-cache によると

Clear cache directory on "postinstall" in package.json.

とある。


その他

キャッシュの更新タイミングは?

明記されていなくて困った。
スライドでも

ファイルのmtimeでキャッシュしとく

とあるが、たしかに実装を見ると mtime で比較しているような箇所がなんとなくある
mtime は更新日時(Modified Time。参考


所感

どちらも複雑な設定は必要なく、追加するだけでビルドの高速化が期待できるというところは良いが
ドキュメントを読んだだけでは細かい挙動まで理解しきれていないので、いざ使ってみたらかえって重くなった、あるいはキャッシュが効きすぎて更新が反映されない、とかハマる可能性はありそう。

webpack-dev-server を使った Development Build 時と Production Build とで loader の有効無効切り替えは必要なのか?と思ったが
どちらも webpack のドキュメントでは #General という章に書かれており、

The following best practices should help whether or not you are in development or building for production.

なので、その心配はなさそうと判断。