CommonsChunkPluginの設定と使い方を詳しく解説
序章
CommonsChunkPlugin は、主にサードパーティのライブラリとパブリック モジュールを抽出するために使用され、最初の画面にロードされるバンドル ファイルや、オンデマンドでロードされるバンドル ファイルが大きすぎてロード時間が長すぎることを回避するために使用されます。最適化のための非常に優れたツールです。 。
まず、CommonsChunkPlugin でさまざまなチュートリアルやドキュメントで言及されているチャンクの種類について説明しますが、主に次の 3 種類があります。
- エントリーチャンク
Webpackに設定されたエントリーファイル(エントリー)がchunkです。 - 子チャンク
エントリ ファイルとその依存ファイルもコード分割 (コード分割) によるチャンクです。 - CommonsChunkPlugin を通じてコモンズ チャンク
によって作成されたファイルもチャンクです。
CommonsChunkPlugin の構成可能なプロパティ:
- name に
は、既存のチャンク (通常はエントリ ファイルを指します) に対応する名前を指定できます。その場合、共通モジュール コードはこのチャンクにマージされます。それ以外の場合は、マージ用に name という名前のコモンズ チャンクが作成されます。 - filename は、
コモンズ チャンクのファイル名を指定します。 - chunks は
ソース チャンクを指定します。つまり、パブリック モジュールを検索するチャンクを指定します。このオプションが省略された場合、デフォルトはエントリ チャンクです。 - minChunks に
は数値、関数、または無限大を指定できます。具体的な使用法と違いについては以下で説明します。
Children と async は非同期アプリケーションに属しており、最後に説明します。
誰もが混乱するだろうと言われるかもしれませんが、デモは上記の特性をテストするために使用されます。
実用化
次のデモでは、主に次の状況をテストします。
- サードパーティのライブラリとカスタムのパブリック モジュールを分離しないでください。
- サードパーティ ライブラリ、カスタム パブリック モジュール、Webpack 実行ファイルは別々ですが、同じファイル内にあります
- 個別のサードパーティ ライブラリ、カスタム パブリック モジュール、および Webpack 実行ファイルを個別に、それぞれ異なるファイルに保存
サードパーティのライブラリとカスタムのパブリック モジュールを分離しないでください。
プロジェクトの初期構造である dist ディレクトリは、パッケージ化後に生成されます。
src ディレクトリ内の各ファイルの内容は、次のように非常に簡潔です。
common.js
export const common = 'common file';
first.js
import {
common} from './common';
import $ from 'jquery';
console.log($,`first ${
common}`);
second.js
import {
common} from './common';
import $ from 'jquery';
console.log($,`second ${
common}`);
package.json ファイル:
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rimraf dist && webpack"
},
"author": "",
"license": "ISC",
"devDependencies": {
"rimraf": "^2.6.2",
"webpack": "^3.10.0",
"webpack-dev-server": "^2.10.1"
},
"dependencies": {
"jquery": "^3.2.1"
}
}
webpack.config.js:
const path = require("path");
const webpack = require("webpack");
const config = {
entry: {
first: './src/first.js',
second: './src/second.js'
},
output: {
path: path.resolve(__dirname,'./dist'),
filename: '[name].js'
},
}
module.exports = config;
次に、コマンド ラインで npm run build を実行します。この時点で、プロジェクトにはさらに dist ディレクトリがあります:
コマンド ラインで webpack のパッケージ化情報を確認してください:
first.js と Second.js を確認してください。参照しているcommon.jsファイルとjqueryは全てパッケージ化するのは絶対に無理です。公開モジュールは繰り返しパッケージ化されており、容量が大きすぎます。
個別のサードパーティ ライブラリ、カスタム パブリック モジュール、および Webpack 実行ファイル
この時点で、webpack.config.js を変更して、エントリ ファイル ベンダーとパブリック モジュールを抽出する CommonsChunkPlugin プラグインを追加します。
webpack.config.js:
const path = require("path");
const webpack = require("webpack");
const packagejson = require("./package.json");
const config = {
entry: {
first: './src/first.js',
second: './src/second.js',
vendor: Object.keys(packagejson.dependencies)//获取生产环境依赖的库
},
output: {
path: path.resolve(__dirname,'./dist'),
filename: '[name].js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: '[name].js'
}),
]
}
module.exports = config;
dist ディレクトリを確認すると、新しい Vendor.js ファイルが追加されています。
コマンド ラインで Webpack のパッケージ化情報を確認してみましょう
。vendor.js ファイルを確認すると、最初のファイルに依存する jquery と common.js を見つけることができます。 js および Second.js ファイル すべては、webpack の実行ファイルとともに、vendor.js にパッケージ化されます。一般に、共通モジュールを抽出するという最初の目標は達成されましたが、それらはすべて同じファイル内にあります。
現時点では、vendor.js が純粋で完璧であること、サードパーティのライブラリのみが含まれていること、カスタムのパブリック モジュールと Webpack 実行ファイルが含まれていないこと、またはサードパーティのライブラリとパブリック モジュールが含まれていることを期待している人もいますが、実際には含まれていません。 Webpack 実行ファイルは含まれません。
実際、この考え方は正しく、特に Webpack 実行ファイルを分離する場合、Webpack 実行ファイルはパックするたびに変更されるため、Webpack 実行ファイルを分離しない場合、vendor.js に対応するハッシュ値は毎回変わります。これにより、vendor.js が変更されますが、実際には、サードパーティのライブラリは変更されていません。ただし、ブラウザは、キャッシュされた元の Vendor.js が無効であると判断するため、サーバーにアクセスして、もう一度入手してください。実際には、これは Webpack 実行ファイルが変更されただけです。誰かにリロードしてもらうのは残念です~
OK、この状況でテストしてみましょう。
個別のサードパーティ ライブラリ、カスタム パブリック モジュール、および Webpack 実行ファイル
ここでは 2 つのステップで説明します。
- まず、Webpack 実行ファイルを個別に抽出します。
- 次に、サードパーティのライブラリとカスタムのパブリック モジュールを分離します。ここで minChunks を使用する方法は 2 つありますが、それについては後ほど説明します。
Webpack実行ファイルを抽出します。
まず、webpack 実行ファイルを抽出し、webpack 構成ファイルを変更します。
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor','runtime'],
filename: '[name].js'
}),
]
実際、上記のコードは次のコードと同等です。
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: '[name].js'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
filename: '[name].js',
chunks: ['vendor']
}),
]
Webpack 実行ファイルのコードを抽出する上記の 2 つの段落は、Webpack 実行ファイルを抽出するために runtime という名前のコモンズ チャンクを作成することを意味します。ソース チャンクは、vendor.js です。
dist ディレクトリを確認すると、runtime.js ファイルが追加されています。これは実際には webpack の実行ファイルです。
コマンド ラインで webpack のパッケージ化情報を再度確認すると、vendor.js のボリュームが減少していることがわかります。 、webpack が実行されたことを示します ファイルが抽出されます:
ただし、vendor.js にはカスタム パブリック モジュール common.js があります。人々は、vendor.js に、プロジェクトが依存するサードパーティ ライブラリを持たせたいだけです (ここでは jquery を使用します) ).このとき、minChunks 属性が導入されます。
minChunks には数値、関数、無限大を設定できます。デフォルト値は 2 で、これは公式ドキュメントに記載されているエントリ ファイルの数ではありません。minChunks の意味は次のとおりです。
- 数値: モジュールが抽出されて共通チャンクになる前に、モジュールによって共通に参照されるチャンクの数
- 関数: 2 つのパラメーター (モジュール、カウント) を受け入れ、ブール値を返します。関数内で指定したロジックを実行して、モジュールがコモンズ チャンクとして抽出されるかどうかを判断できます。
- Infinity: エントリ チャンクが 3 以上の場合にのみ有効で、サードパーティ ライブラリ内のカスタム パブリック モジュールを分離するために使用されます。
サードパーティのライブラリとカスタムのパブリック モジュールを抽出する
サードパーティのライブラリをvendor.jsから分離するには、上記の2つの方法があります。
最初の方法
MinChunks が Infinity に設定されている場合は、webpack 構成ファイルを次のように変更します。
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor','runtime'],
filename: '[name].js',
minChunks: Infinity
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
filename: '[name].js',
chunks: ['first','second']//从first.js和second.js中抽取commons chunk
}),
]
dist ディレクトリを確認すると、common.js ファイルが追加されています。
コマンド ラインで Webpack パッケージ情報を再度確認してみましょう。カスタム パブリック モジュールが分離されています。
現時点では、vendor.js は純粋で完璧で、3 番目のファイルのみが含まれています。 -party ライブラリ ファイル、common.js はカスタム パブリック モジュール、runtime.js は webpack の実行ファイルです。
2番目の方法
それらを分離するには、minChunks を関数として使用します。関数の 2 つのパラメーターとしての minChunks の意味について説明します。
- module: 現在のチャンクとそれに含まれるモジュール
- count: 現在のチャンクとそれに含まれるモジュールが参照された回数
関数として、minChunks は各エントリ ファイルとその依存モジュールを走査し、ブール値を返します。true の場合は、現在処理中のファイル (module.resource) がコモンズ チャンクにマージされていることを意味します。 false の場合、マージされません。
引き続き Webpack 設定ファイルを変更し、ベンダー エントリ ファイルをコメント アウトし、関数として minChunks を使用して、ベンダーにサードパーティ ライブラリのみが含まれていることを認識し、上記と同じ効果を実現します。
const config = {
entry: {
first: './src/first.js',
second: './src/second.js',
//vendor: Object.keys(packagejson.dependencies)//获取生产环境依赖的库
},
output: {
path: path.resolve(__dirname,'./dist'),
filename: '[name].js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: '[name].js',
minChunks: function (module,count) {
console.log(module.resource,`引用次数${
count}`);
//"有正在处理文件" + "这个文件是 .js 后缀" + "这个文件是在 node_modules 中"
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, './node_modules')) === 0
)
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
filename: '[name].js',
chunks: ['vendor']
}),
]
}
上記のコードは、実際にはベンダーと呼ばれるコモンズ チャンクを生成するものですが、どのモジュールがベンダーに追加されるのでしょうか? エントリ ファイルとその依存モジュールをトラバースするだけです。モジュールが js ファイルで、node_modules にある場合、ベンダーに追加されます。実際、これはベンダーがサードパーティ ライブラリのみを保持する方法でもあります。
コマンドラインで webpack のパッケージ化情報を再度確認してみましょう。
上記の minChunks を Infinity に設定した結果と一致していることがわかります。
子と非同期属性
これら 2 つの属性は主にコード分割 (コード分割) と非同期読み込みで使用されます。
- Children 1.1 が true と指定された
場合、ソース チャンクがエントリ チャンク (エントリ ファイル) を介してコード分割された子チャンクであることを意味します。
1.2 子とチャンクは両方ともソース チャンクを指定するため、同時に設定できません。
1.3 の子を使用して、エントリ チャンクによって作成された子チャンクの共有モジュールをそれ自体にマージできますが、これにより初期ロード時間が長くなります。 - async は、
children: true がエントリ チャンク自体にマージされる場合に、初期読み込み時間が長すぎるという問題を解決します。async が true に設定されている場合、コモンズ チャンクはそれ自体にマージされませんが、新しい非同期コモンズ チャンクが使用されます。子チャンクがダウンロードされると、コモンズ チャンクも自動的に並行してダウンロードされます。
次のように、Webpack 構成ファイルを変更し、chunkFilename を追加します。
output: {
...........
chunkFilename: "[name].[hash:5].chunk.js",
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor','runtime'],
filename: '[name].js',
minChunks: Infinity
}),
new webpack.optimize.CommonsChunkPlugin({
children: true,
async: 'children-async'
})
]
chunkFilename は、非同期的にロードされるモジュールの名前を指定するために使用されます。非同期的にロードされるモジュール内で共通に参照されるモジュールは、名前 (children-async) を指定するために async にマージされます。
非同期スクリーンショットに変更するのは面倒なので簡単に説明すると、1 つ目と 2 つ目は非同期読み込みモジュールで、どちらも common.js モジュールを参照しています。このステップを設定しない場合:
new webpack.optimize.CommonsChunkPlugin({
children: true,
async: 'children-async'
})
次に、共通に参照される common.js がそれぞれのモジュールにパッケージ化され、繰り返しパッケージ化されます。
OK、設定後は、子供の顔がどのように分割されるかにも依存します。
- Children が true の場合、共通に参照されるモジュールはパッケージ化され、children-async という名前のパブリック モジュールにマージされます。最初または 2 番目に遅延ロードするときに、このパブリック モジュールと Children-async パブリック モジュールを並行してロードします。
- Children は false で、共通に参照されるモジュールは最初の画面にロードされる app.bundle にパッケージ化されます。これにより、最初の画面のロードに時間がかかりすぎて使用されなくなるため、true に設定することをお勧めします。
ブラウザキャッシュの実装
まずハッシュ値の違いについて話しましょう。
- ハッシュはビルド固有です。つまり、各コンパイルが異なります - 開発段階に適しています
- chunkhash はチャンク固有であり、各チャンクの内容に基づいて計算されたハッシュであり、運用環境に適しています。
したがって、実稼働環境では、ブラウザーのキャッシュを最大限に使用するために、ファイル名を「[name].[chunkhash]」に変更する必要があります。
最後に、この記事を書くにあたり、私自身多くのデモをテストしてきましたが、もちろんすべてを掲載することは不可能ですが、今後もさらにハンズオン テストを行っていきたいと考えています。
https://github.com/creeperyang/blog/issues/37
https://segmentfault.com/q/1010000008726439/revision#r4
https://segmentfault.com/q/1010000009070061
https://www.jianshu.com /p/2b81262898a4
ありがとう
著者である Yanglinxiaoに心から感謝します。「CommonsChunkPlugin」に関する私の混乱に答えた素晴らしい記事を提供してくれました。
https://segmentfault.com/a/1190000012828879