この記事は、私が Webpack4 を使用している中で得たいくつかのまとめであり、Webpack のビルド速度を最適化するための方法を紹介しています。
Webpack は現在最も人気のあるパッケージングツールであり、最新バージョンは Webpack4 + です。パフォーマンスが大幅に向上しています。この記事は、私が使用している中で得たいくつかのまとめであり、主に Webpack のビルドパフォーマンスを向上させることを目的としています。
最新バージョンの使用#
最新の Webpack バージョンを使用してください。新しいバージョンでは通常、パフォーマンスが最適化されています。
Node.js の最新バージョンを使用することもパフォーマンスを向上させることができます。また、パッケージ管理ツール(例:npm または yarn)も最新のものを使用することでパフォーマンスが向上します。新しいバージョンでは、より効率的なモジュール依存関係のツリーの構築や解析速度の向上が可能です。
Loader での include または exclude の使用#
Loader を設定する際に、include を使用すると処理するディレクトリをより正確に指定できます。これにより、不要な走査を減らし、パフォーマンスの低下を防ぐことができます。同様に、明確に処理する必要のないディレクトリは除外する必要があります。これにより、Webpack のパッケージ最適化速度がさらに向上します。include と exclude を適切に設定することで、Webpack のパッケージ最適化速度が大幅に向上します。
module.exports = {
//...
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
loader: 'babel-loader'
}
]
}
};
解析速度の向上#
以下の手順により解析速度を向上させることができます:
- resolve.modules、resolve.extensions、resolve.mainFiles、resolve.descriptionFiles の各項目の数をできるだけ減らすようにします。これらはファイルシステムの呼び出し回数を増やすためです。
- symlinks を使用していない場合は、resolve.symlinks: false を設定できます(例:npm link または yarn link)。
- カスタム解析プラグインを使用しており、コンテキスト情報を指定していない場合は、resolve.cacheWithContext: false を設定できます。
module.noParse#
指定された正規表現に一致するファイルを Webpack が解析しないようにします。無視されるファイルには import、require、define の呼び出しや他のインポートメカニズムが含まれていないはずです。大規模なライブラリを無視することでビルドパフォーマンスが向上します。
module.exports = {
//...
module: {
noParse: /jquery|lodash/,
// webpack 3.0.0以降
noParse: function(content) {
return /jquery|lodash/.test(content);
}
}
};
babel-loader#
babel-loader のビルドは遅いため、exclude、include を使用して処理するディレクトリをできるだけ正確に指定するだけでなく、キャッシュを最大限に活用してパフォーマンスを向上させる必要があります。babel-loader は cacheDirectory オプション(デフォルトは false)を提供しており、設定されている場合、指定されたディレクトリを使用して loader の実行結果をキャッシュします。その後の Webpack のビルドでは、キャッシュを読み取って Babel の再コンパイルによる高性能消費を回避します。
cacheDirectory オプションを使用することで、babel-loader の速度を少なくとも 2 倍に向上させることができます。これにより、変換結果がファイルシステムにキャッシュされます。
babel は各ファイルにヘルパーコードを挿入し、コードサイズが大きくなります!
babel は、_extend などの一部の共通メソッドに非常に小さなヘルパーコードを使用しています。デフォルトでは、それらは必要なファイルに追加されます。
重複したインポートを避けるために、babel ランタイムを独立したモジュールとしてインポートすることができます。
以下の設定では、babel 自体が各ファイルにランタイムを自動的に注入するのを無効にし、babel-plugin-transform-runtime をインポートし、すべてのヘルパーコードをここから参照します。
rules: [
// 'transform-runtime'プラグインは、babelにruntimeを参照するように指示します。
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/transform-runtime']
}
}
}
]
Dlls#
変更が頻繁でないコードを DllPlugin を使用して個別にコンパイルします。これにより、アプリケーションのコンパイル速度が向上しますが、ビルドプロセスが複雑になる可能性もあります。
Happypack によるマルチスレッドビルド#
Node.js のシングルスレッド制限のため、すべての loader は async 形式で並行して呼び出されますが、まだ単一のノードプロセスで実行され、同じイベントループで実行されます。これにより、次のような問題が発生します:複数の loader ファイルリソースを同時に読み取る場合、たとえば babel-loader はさまざまな jsx、es6 のリソースファイルを変換する必要があります。このような CPU 集中型のシナリオでは、Node のシングルスレッドモデルには利点がありませんが、Happypack はこのような問題を解決するために作成されました。
Happypack の処理方法は、Webpack が loader の実行プロセスを単一のプロセスから複数のプロセスモードに拡張することで、コードのビルドを高速化することです。元のフローは変わらず、既存の設定を変更せずにビルドプロセスを最適化することができます。具体的な設定は以下の通りです:
// webpack.config.js
const HappyPack = require('happypack');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
exports.module = {
rules: [
{
test: /.js$/,
include: [resolve('src')],
exclude: /node_modules/,
loader: 'happypack/loader?id=happybabel'
}
]
};
exports.plugins = [
new HappyPack({
id: 'happybabel',
loaders: ['babel-loader'],
threadPool: happyThreadPool,
cache: true,
verbose: true
})
];
Happypack は、ビルドプロセスを高速化するためにマルチスレッドモードを使用するだけでなく、キャッシュ計算も同時に有効にし、ビルド速度の向上にも非常に効果的です。