[轉]webpack——CommonsChunkPlugin

做用
雖然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

相關文章
相關標籤/搜索