Webpack CommonsChunkPlugin 理解

 

最近讀了一下webpack的文檔,讀到CommonsChunkPlugin這個插件,深深折服與webpack的強大,同時也產生了一些本身的疑問。webpack

 

首先,CommonsChunkPlugin這個插件是用來提取公共代碼的,經過將公共模塊提取出來,只在頁面加載的時候引入一次,提高應用的加載效率。web

順便提一下,chunk其實就是代碼塊的意思,多是一個或多個模塊,通常就是一個js文件。緩存

 

CommonsChunkPlugin有中文翻譯的文檔,可是感受並非很通順,英文文檔看完也有一些疑惑,好比minChunks究竟是作什麼用的,怎麼用?chunks是什麼?首先貼一下文檔。app

 1 {
 2   name: string, // or
 3   names: string[],
 4   // The chunk name of the commons chunk. An existing chunk can be selected by passing a name of an existing chunk.
 5   // If an array of strings is passed this is equal to invoking the plugin multiple times for each chunk name.
 6   // If omitted and `options.async` or `options.children` is set all chunks are used, otherwise `options.filename`
 7   // is used as chunk name.
 8   // When using `options.async` to create common chunks from other async chunks you must specify an entry-point
 9   // chunk name here instead of omitting the `option.name`.
10 
11   filename: string,
12   // The filename template for the commons chunk. Can contain the same placeholders as `output.filename`.
13   // If omitted the original filename is not modified (usually `output.filename` or `output.chunkFilename`).
14   // This option is not permitted if you're using `options.async` as well, see below for more details.
15 
16   minChunks: number|Infinity|function(module, count) -> boolean,
17   // The minimum number of chunks which need to contain a module before it's moved into the commons chunk.
18   // The number must be greater than or equal 2 and lower than or equal to the number of chunks.
19   // Passing `Infinity` just creates the commons chunk, but moves no modules into it.
20   // By providing a `function` you can add custom logic. (Defaults to the number of chunks)
21 
22   chunks: string[],
23   // Select the source chunks by chunk names. The chunk must be a child of the commons chunk.
24   // If omitted all entry chunks are selected.
25 
26   children: boolean,
27   // If `true` all children of the commons chunk are selected
28 
29   async: boolean|string,
30   // If `true` a new async commons chunk is created as child of `options.name` and sibling of `options.chunks`.
31   // It is loaded in parallel with `options.chunks`.
32   // Instead of using `option.filename`, it is possible to change the name of the output file by providing
33   // the desired string here instead of `true`.
34 
35   minSize: number,
36   // Minimum size of all common module before a commons chunk is created.
37 }
  • namenames:chunk的名稱,若是這個chunk已經在entry中定義,該chunk會被直接提取;若是沒有定義,則生成一個空的chunk來提取其餘全部chunk的公共代碼。
  • filename:能夠指定提取出的公共代碼的文件名稱,可使用output配置項中文件名的佔位符。未定義時使用name做爲文件名。
  • chunks:能夠指定要提取公共模塊的源chunks,指定的chunk必須是公共chunk的子模塊,若是沒有指定則使用全部entry中定義的入口chunk。
  • minChunks:在一個模塊被提取到公共chunk以前,它必須被最少minChunks個chunk所包含。(通俗的說就是一個模塊至少要被minChunks個模塊所引用,才能被提取到公共模塊。)async

該數字必須不小於2或者不大於chunks的個數。默認值等於chunks的個數。this

若是指定了Infinity,則建立一個公共chunk,可是不包含任何模塊,內部是一些webpack生成的runtime代碼和chunk自身包含的模塊(若是chunk存在的話)。spa

用戶也能夠定製本身的邏輯去生成代碼。插件

 

咱們看一個簡單的例子。翻譯

 1 module.exports = {
 2     entry: {
 3         app: './src/index.js',
 4         vender: [
 5             'lodash',
 6             'otherlib'
 7         ]
 8     },
 9     plugins: [
10         new webpack.optimize.CommonsChunkPlugin({ 11             name: 'vender'
12  }) 13     ],
14     output: {
15         filename: '[name].[chunkhash].js',     // 使用Hash來命名文件,實現文件緩存的功能。當文件內容發生變化,文件名會隨之改變。 16         path: path.resolve(__dirname, 'dist')
17     }
18 };

上面的代碼中定義了兩個入口,app和vender(公共庫),plugins中使用CommonsChunkPlugin提取vender。code

 

vender是咱們提取出來的公共chunk,一般不會被修改,因此理應在每次編譯後文件名保持一致。然而,咱們嘗試修改入口文件index.js會發現,vender的文件名會發生變化。

緣由呢上面提到過,因爲每次編譯會致使vender的module.id發生變化,內部的runtime代碼隨之發生改變。

 

解決方案有如下幾種:

  1. 使用NamedModulesPlugin插件,用文件路徑而非默認的數字ID來做爲模塊標識。

  2. 使用HashedModuleIdsPlugin插件,用相對路徑的Hash值來做爲模塊標識。推薦在生產環境中使用。

  3. 將runtime部分的代碼提取到一個單獨的文件中,代碼以下。

 1 module.exports = {
 2     entry: {
 3         app: './src/index.js',
 4         vender: [
 5             'lodash'
 6         ]
 7     },
 8     plugins: [
 9         new webpack.optimize.CommonsChunkPlugin({
10             name: 'vender',
11             minChunks: Infinity
12         }),
13         new webpack.optimize.CommonsChunkPlugin({ 14             name: 'manifest', 15             chunks: ['vender'] 16  }) 17     ],
18     output: {
19         filename: '[name].[chunkhash].js',
20         path: path.resolve(__dirname, 'dist')
21     }
22 };

代碼中再次使用了CommonsChunkPlugin,從vender中提取出了名爲manifest的運行時代碼。

 

 

未完待續,歡迎指正。

相關文章
相關標籤/搜索