做用
雖然webpack4已經出來好久了,CommonsChunkPlugin也已經捨棄了,可是仍是有不少項目是經過webpack3來打包的,對CommonsChunkPlugin各個配置項的認識仍是比較模糊,這裏作個詳細的記錄。vue
CommonsChunkPlugin經過將公共模塊拆出來,最終合成的文件可以在最開始的時候加載一次,以便存到緩存中供後續使用。node
既然是將公共模塊拆分出來,那麼確定是要有多個被打包的模塊,即公共模塊的來源,包括 入口文件和 已近提取出來的公共模塊,若是來源只有一個,那麼就當即被打包成一個單獨文件,不會抽取公共模塊,由於一個chunk來源是不會出現公共模塊的,這是webpack打包策略,只會出現各個組件的相互引用,這種狀況用於提取第三方庫等;若是來源不少個,那麼會提取出公共的模塊組成一個單獨的文件,來源文件再各自打包成各自的單獨文件
這裏最重要的是搞清楚的就是配置項中各類chunk的概念和來源,咱們首先看看有哪些配置選項。再對配置項逐一解析。jquery
用法webpack
new webpack.optimize.CommonsChunkPlugin(options);
options選項及官方翻譯web
{ name: string, // or names: string[], /*name或者names是入口文件中的chunk名稱,公共模塊chunk能夠在入口文件中定義名稱和所對應的模塊,而後被選擇; *name和names的不一樣在於:name只選擇一個入口chunk進行分開打包,names至關於name的遍歷版, *對names數組中的chunk遍歷,而後單獨打包,此時options.filename不能是具體的名稱,某則會出現相同的名稱而報錯, * */ // 若是該選項被忽略,同時 `options.async` 或者 `options.children` 被設置,全部的 chunk 都會被使用, // 不然 `options.filename` 會用於做爲 chunk 名。 filename: string, /*文件的名字模板,可使用和output相同的佔位符,如[hash:7],7表明7位hash符號,默認是20位; * 默認名字與`output.filename` 或者 `output.chunkFilename`相同*/ minChunks: number|Infinity|function(module, count) => boolean, // 在傳入 公共chunk(commons chunk) 以前所須要包含的最少數量的 chunks 。 // 數量必須大於等於2,或者少於等於 chunks的數量 // 傳入 `Infinity` 會立刻生成 公共chunk,但裏面沒有模塊。 // 你能夠傳入一個 `function` ,以添加定製的邏輯(默認是 chunk 的數量) /*module.context表明chunk因此在的文件夾路勁, *module.resource表明該chunk的文件路勁 *count chunk被引入的次數*/ chunks: string[], // 經過 chunk name 去選擇 chunks 的來源。chunk 必須是 公共chunk 的子模塊。 // 若是被忽略,全部的,全部的 入口chunk (entry chunk) 都會被選擇。 /*chunks和children是相同的做用,不一樣的是chunks只選擇特定的子模塊抽取公共模塊, *而children是選擇全部的子模塊*/ children: boolean, // 若是設置爲 `true`,全部公共 chunk 的子模塊都會被選擇 /*將子模塊的公共模塊打包進父 chunk */ deepChildren: boolean, // 若是設置爲 `true`,全部公共 chunk 的後代(子孫)模塊都會被選擇 async: boolean|string, // 若是設置爲 `true`,一個異步的 公共chunk 會做爲 `options.name` 的子模塊,和 `options.chunks` 的兄弟模塊被建立。 // 它會與 `options.chunks` 並行被加載。 minSize: number, // 在 公共chunk 被建立立以前,全部 公共模塊 (common module) 的最少大小。 }
配置項介紹
不按照上面的順序介紹,有些配置項很類似,容易弄混,按照我本身理解來解釋。vue-router
1. filename
這是文件名的模板,和output.filename 或者 output.chunkFilename是一個意思,最終生成的文件名。數組
若是配置了這個項,以這個模板優先取名,不然,按照output.filename 或者 output.chunkFilename規則取名。緩存
2. name or names
這個抽取的公共模塊的名字,這個和filename仍是有區別的,filename=name+hash+其它可能的配置項+ext。
example1: 這裏adminA和adminB都引入的common.js,因此會抽取common.js做爲公共模塊。app
//adminA require("./common") console.log("adminA")
//adminA require("./common") console.log("adminB")
entry: { adminA: "./adminA", adminB: "./adminB", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: "commons", }), ]
打包生成名爲 commons的公共模塊echarts
同時,若是這個name和入口文件的name相同,那麼入口文件直接被選擇爲打包來源,即直接指定name所指定的入口文件爲公共模塊;這個在很明確公共模塊是什麼的時候頗有用,好比第三方庫,能夠直接指定。
names則是經過遍歷names數組,執行屢次該插件,免去寫多個相同的代碼(若是有這個需求)。例:
example2: 增長adminC,可是沒有引入common.js,只有adminA和adminB引入了。
//adminC console.log("adminC");
entry: { adminA: "./adminA", adminB: "./adminB", adminC: "./adminC", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, plugins: [ new BundleAnalyzerPlugin(), new webpack.optimize.CommonsChunkPlugin({ name: "commons", }), ]
雖然也生成了commons.js可是其實裏面沒有任何東西(文件很小),adminA和adminB文件仍是很大,也就是沒有抽取公共模塊:
能夠用插件webpack-bundle-analyzer分析:common.js仍是存在adminA.js和adminB.js裏面
這個時候在入口文件直接指定公共模塊commons:
example3
entry: { adminA: "./adminA", adminB: "./adminB", adminC: "./adminC", //name和配置項的name相同 commons: './common.js' },
能夠從文件大小看出來,公共模塊已經抽取出來了。
3. minChunks
被其餘模塊引用的次數 (默認是3),只有知足這個引入次數條件纔會被抽取,若是設置成 Infinity (無限大,不可能知足),那麼會當即打包成一個獨立模塊,不會抽取公共模塊,用於公共模塊很明確的時候或者想直接打包某一chunk。
例如前面的example2,也能夠不用在入口指定公共模塊,主要是由於minChunk的默認值是3,而common.js只被adminA和adminB引入了,也就是隻引入了兩次,因此不會被打包,咱們這裏將example2的minChunks設置2,再打包:
example4:
entry: { adminA: "./adminA", adminB: "./adminB", adminC: "./adminC", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, plugins: [ new BundleAnalyzerPlugin(), new webpack.optimize.CommonsChunkPlugin({ name: "commons", minChunks: 2 }), ]
從文件大小上能夠看出,common.js已經抽取出來了:
minChunks也能夠是一個函數,webpack會遍歷全部來源chunk,逐一執行這個函數,函數返回true這個chunk才被提取爲公共模塊。這個函數用於更加精確的提取公共模塊,如vue構建工具生成的配置文件,能夠提取全部在文件夾node_modules中的模塊:
example5:
//這裏是提取全部的第三方插件,如我這裏有vue,vue-router,echarts //可是echarts太龐大了,須要和vue,vuer-router分離 new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks(module) { /*module.context表明chunk因此在的文件夾路勁, *module.resource表明該chunk的文件路勁 *count chunk被引入的次數*/ return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '../node_modules') ) === 0 ) }, chunks: ["app"] }), //分離vue,vue-router,echarts是按需引入的,不太方便按這種方式抽取。 new webpack.optimize.CommonsChunkPlugin({ name: 'vue', minChunks: function (module) { return (module.resource && /\.js$/.test(module.resource) && (/vue/).test(module.resource)) }, chunks: ['vendor'] }),
4. chunks
選擇chunk來源,即選擇要被抽取的模塊來源,這個很好理解,即被選擇的chunk來源纔會被抽取公共模塊。如:A和B同時引入C,而D沒有引入C,那麼就能夠只選擇A和B做爲chunk來源,抽取A、B的公共模塊C,不然C可能不會被抽取爲公共模塊。
eample6: adminA、adminB和adminC都引入common.js,可是chunks只選擇adminA和B。
entry: { adminA: "./adminA", adminB: "./adminB", adminC: "./adminC", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, plugins: [ new BundleAnalyzerPlugin(), new webpack.optimize.CommonsChunkPlugin({ name: "commons", minChunks: 2, chunks: ['adminA', 'adminB'] }), ]
結果:adminA和adminB的common.js被抽取出來了,可是adminC的common.js沒有被抽取出來(從大小上判斷)。
5. children
children: webpack官方給出了一個案例,中文版是翻譯過來的,可是我看了好久都沒看明白,其實翻譯是不夠嚴謹的,案例中翻譯說 一個 chunk的子模塊會有公共模塊,配置參數裏面翻譯是公共模塊的子模塊會有公共依賴,我想了很久,都沒想出這個子模塊是什麼意思;實際上是 一個入口的模塊的子模塊,子模塊指的是 異步加載模塊、經過代碼分割功能從這個入口chunk分離出來的chunk,在模塊中使用import()或者require.ensure(),會單獨打包這一部分模塊。
eample7: adminA經過代碼分割功能,異步加載childA和childB,childA和childB都引入了jquery和common。
//adminA.js import('./childA'); import('./childB'); console.log("adminA");
//chuildA import './jquery'; import './common'; console.log('childA');
//chuildB import './jquery'; import './common'; console.log('childB');
//webpack.config.js entry: { adminA: "./adminA", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js", chunkFilename: '[name].chunk.js' }, plugins: []
不優化的打包結果:生成了兩個異步的chunk,0和1,就是childA和childB。childA和childB都引入了common.js和jquery.js,體積很大。
咱們試着優化,看能不能把異步加載的模塊的公共模塊抽取出來:
eample8:
//webpack.config.js entry: { adminA: "./adminA", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js", chunkFilename: '[name].chunk.js' }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: "commons", minChunks: 2 }),
]
結果:common.js和jquery.js並無抽取出來成爲公共模塊,只是抽取了webpack代碼分離功能的代碼,由於代碼分離出來的chunk,並不在chunk來源選擇範圍內(忽略了chunks選項,那麼默認是所有的chunk來源,可是排除代碼分離的chunk)。
咱們加上children:true,而且須要把name設置成入口chunk的name,此處是adminA:
eample9:
//webpack.config.js entry: { adminA: "./adminA", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js", chunkFilename: '[name].chunk.js' }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: "adminA", minChunks: 2, children: true }),
]
結果:common.js和jquery.js被打包進了adminA,也就是代碼分離後子模塊的公共模塊被打包進了父模塊。減小了整體體積。可是會增長初始加載時間(即加載adminA的時間會延長),若是分離子模塊的公共代碼不少,而且預計到用戶會加載不少子模塊(代碼分離的子模塊),能夠這樣作。固然,還有另一種方法,就是async.
6.async
async: 就是把代碼分離模塊的公共模塊抽取出來。不一樣於上面children:true是把公共模塊抽取放到父模塊中,async:true把公共模塊單獨抽取出來做爲一個公共模塊,和以前抽取公共模塊是同樣的,只不過這個抽取的是分離代碼的公共模塊。
再看**example10:**在example9的基礎上加上async,async能夠取值Boolean值也能夠是string,若是是string,那麼這個string值做爲chunk打包後的name,若是是Boolean值,那麼打包後的name就是0。
一樣,這裏的options.name要和入口chunk的name匹配
entry: { adminA: "./adminA", }, output: { path: path.join(__dirname, "dist"), filename: "[name].js", chunkFilename: '[name].chunk.js' }, plugins: [ new BundleAnalyzerPlugin(), new webpack.optimize.CommonsChunkPlugin({ //要和入口chunk的name匹配 name: "adminA", minChunks: 2, children: true, async: "async-chunk" }), ]
名爲async-chunk.chunk.js就是咱們分離代碼的公共模塊。
7.minSize
抽取公共代碼以前,應該知足的文件的大小。若是抽取出來的公共代碼文件大小隻有幾kb,這樣會增長請求次數,還不如不抽取。
8.deepChildren
這個目前還不知道有什麼用,和children差很少,children選擇的是直接子代,deepChildren選擇的是全部後代,可是目前我並無發現它有什麼用。
原文連接:https://blog.csdn.net/zy444263/article/details/85252477