下記ページのざっくりとした翻訳。
ビルド/コンパイルのパフォーマンスを向上させるために役立つヒント。
General
開発用、本番用の両方のビルドで役立つベストプラクティスの紹介
Stay Up to Date(最新に保つ)
最新の webpack、node.js、npm or yarn を使う(常にパフォーマンスの改善を図っているため)
Loaders
必要最小限の数のモジュールにローダーを適用する。
下記のように、include
を使うとそのディレクトリ配下のみに適用されるので効率が良い。
▼ webpack.config.js
module.exports = {
//...
module: {
rules: [
{
test: /\.js$/,
+ include: path.resolve(__dirname, 'src'),
loader: 'babel-loader'
}
]
}
};
Bootstrap
追加のローダー/プラグインにはそれぞれ起動に時間がかかる。できるだけ少ないツールを使用するようにする。
Resolving
下記手順で解決速度を上げることができる
- ファイルシステムの呼び出し数が増えるにつれて、
resolve.modules
、resolve.extensions
、resolve.mainFiles
、resolve.descriptionFiles
の項目数を最小限にする - シンボリックリンクを使用しない場合は、
resolve.symlinks:false
を設定する(例:npm link
oryarn link
) - カスタム解決プラグインを使用する場合、
resolve.cacheWithContext:false
を設定する。これはコンテキスト固有ではない
Dlls
DllPlugin を使用して、あまり頻繁に変更されないコードを別のコンパイルに移動することでアプリケーションのコンパイル速度が向上する。
しかしビルドプロセスが複雑になる。
具体的な使い方などは下記記事が参考になりそう。
webpackのDLLバンドルを使ってビルドを速くする - Qiita
Smaller = Faster
コンパイルの合計サイズを小さくすると、ビルドパフォーマンスが向上する。
チャンクを小さくするようにする。
- 小さなライブラリを使う
- 複数ページのアプリケーションでは、splitChunksPluginを使う
async
モードで使う
- 不要なコードの削除
- 現在開発しているコードの一部をコンパイルする
Worker Pool
現時点でよくわからないので省略
Persistent cache(永続キャッシュ)
cache-loader
で永続的なキャッシュを有効にする。
package.json の postinstall
コマンドを使って、キャッシュディレクトリを削除する。
※postinstall
コマンドとは npm install
コマンドの終了時に実行されるコマンドのこと
Development
開発時に役立つヒントの紹介
Incremental Builds
- WebPackの watch モードを使用する
Compile in Memory
下記のユーティリティは、ディスクに書き込むのではなく、メモリ内のアセットをコンパイルして提供することでパフォーマンスを向上させている
- webpack-dev-server
- webpack-hot-middleware
- webpack-dev-middleware
stats.toJson speed
webpack 4はデフォルトでは stats.toJson()
で大量のデータを出力する。
リビルドのステップで必要な場合を除き、statsオブジェクトの一部を取得しないこと。
v3.1.3以降のwebpack-dev-serverには、リビルドのステップごとにstatsオブジェクトから取得されるデータ量を最小限に抑えるための大幅なパフォーマンス修正が含まれている。
Devtool
異なるdevtool設定のパフォーマンスの違いに注意
eval
は最高のパフォーマンスを発揮するがコード変換には役立たないcheap-source-map
は、多少悪いマッピングで大丈夫であれば、より高性能である- リビルドには
eval-source-map
の変種を使用する
ほとんどの場合、cheap-module-eval-source-map
が最良の選択肢。
Avoid Production Specific Tooling(production 固有のツールを避ける)
特定のユーティリティ、プラグイン、およびローダーは、本番用にビルドするときにのみ意味がある。
たとえば、開発中に TerserPlugin
を使用してコードを縮小したり壊したりしても意味がない。これらのツールは通常、開発から除外する必要がある。
TerserPlugin
ExtractTextPlugin
[hash]/[chunkhash]
AggressiveSplittingPlugin
AggressiveMergingPlugin
ModuleConcatenationPlugin
Minimal Entry Chunk
現時点でよく分からないので省略
Avoid Extra Optimization Steps(余分な最適化手順を避ける)
webpackはサイズと負荷パフォーマンスのために出力を最適化するために余分なアルゴリズムの働きをする。これらの最適化は、小規模のコードベースではパフォーマンスに優れているが、規模の大きいコードベースではコストがかかる可能性がある
▼ 最適化をしない設定
module.exports = { // ... optimization: { removeAvailableModules: false, removeEmptyChunks: false, splitChunks: false, } };
Output Without Path Info
webpackには、出力バンドルにパス情報を生成する機能がある。しかし、これは何千ものモジュールを束ねる大きなプロジェクトにガベージコレクションのプレッシャーをかける。 options.output.pathinfo
設定でこれをオフにする。
module.exports = { // ... output: { pathinfo: false } };
Node.js Version
Node.jsの ver 8.9.10 - 9.11.1
の間で、ES2015の Map
と Set
の実装にパフォーマンス低下のリグレッションがあった。
リビルドの速度改善を望む場合、上記のバージョンを使用するのを避けた方が良い。
TypeScript Loader
ts-loader は内部の TypeScript watch mode APIs を使い始めた。これにより、各反復で再構築されるモジュールの数が劇的に減少した。
この experimentalWatchApi
は、通常のTypeScript watch mode自体と同じロジックを共有しており、開発用には非常に安定している。さらに高速なインクリメンタルビルドを行うには、 transpileOnly
をオンにする。
module.exports = { // ... test: /\.tsx?$/, use: [ { loader: 'ts-loader', options: { transpileOnly: true, experimentalWatchApi: true, }, }, ], };
注:ts-loaderのドキュメントでは cache-loader
の使用を推奨しているが、これは実際にはディスクへの書き込みによるリビルドを遅くする。
再度タイプチェックを行うには ForkTsCheckerWebpackPlugin
を使用する。
完全な例は下記より参照。
ts-loader/examples/fork-ts-checker-webpack-plugin at master · TypeStrong/ts-loader · GitHub
Production
本番用に役立つヒントの紹介
※小さなパフォーマンスの向上のためにアプリケーションの品質を犠牲にしないこと。最適化品質は、ほとんどの場合、ビルドパフォーマンスよりも重要であることに留意すること。
Multiple Compilations
複数のコンパイルを使用する場合は、次のツールが役立つ
Source Maps
source map は重いので本当に必要でなかったら使わない
Specific Tooling Issues(特定のツールのイシュー)
下記ツールには、ビルドパフォーマンスを低下させる可能性のある特定の問題がある
Babel
- プリセット/プラグインの数を最小限にする
TypeScript
- 別のプロセスでタイプチェックするために
fork-ts-checker-webpack-plugin
を使用する - タイプチェックをスキップするようにローダーを設定する
happyPackMode:true
/transpileOnly:true
でts-loader
を使用する
Sass
node-sass
に Node.jsスレッドプールからのスレッドをブロックするバグがある。使うときは thread-loader
を workerParallelJobs: 2
にセットして使う。