最近讀了一下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 }
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的運行時代碼。
未完待續,歡迎指正。