Webpack 理解 Chunk

指望

但願讀過本篇文章,你在看Webpack配置的時候,能在腦中造成Chunk的生成過程。css

Chunk

Chunk不一樣於entry、 output、module這樣的概念,它們對應着Webpack配置對象中的一個字段,Chunk沒有單獨的配置字段,可是這個詞出如今CommonsChunkPlugin(Webpack3之前)、optimization.splitChunks(Webpack4之後)這樣的名稱之中。vue

Chunk是咱們理解Webpack,必須理解的一個概念。node

Chunk在Webpack裏指一個代碼塊,那具體是指什麼樣的代碼塊呢?react

Chunk VS Module

Module

首先來講module,Webpack能夠看作是模塊打包機,咱們編寫的任何文件,對於Webpack來講,都是一個個模塊。因此Webpack的配置文件,有一個module字段,module下有一個rules字段,rules下有就是處理模塊的規則,配置哪類的模塊,交由哪類loader來處理。webpack

module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: "style-loader"
          }, {
            loader: "css-loader"
          }
        ]
      },
      ...
    ]
  },
複製代碼

Chunk

Chunk是Webpack打包過程當中,一堆module的集合。咱們知道Webpack的打包是從一個入口文件開始,也能夠說是入口模塊,入口模塊引用這其餘模塊,模塊再引用模塊。Webpack經過引用關係逐個打包模塊,這些module就造成了一個Chunk。web

若是咱們有多個入口文件,可能會產出多條打包路徑,一條路徑就會造成一個Chunk。出了入口entry會產生Chunk,還有兩種途徑,下面會有介紹。數組

Chunk VS Bundle

一般咱們會弄混這兩個概念,覺得Chunk就是Bundle,Bundle就是咱們最終輸出的一個或多個打包文件。確實,大多數狀況下,一個Chunk會生產一個Bundle。但有時候也不徹底是一對一的關係,好比咱們把 devtool配置成'source-map'。而後只有一個入口文件,也不配置代碼分割:瀏覽器

// webpack配置
 entry: {
    main: __dirname + "/app/main.js",
 },
 output: {
    path: __dirname + "/public",//打包後的文件存放的地方
    filename: "[name].js", //打包後輸出文件的文件名
  },
 devtool: 'source-map',
複製代碼

這樣的配置,會產生一個Chunk,可是會產生兩個bundle,以下圖 bash

image
注意到Chunk Names那列,只有main這麼一個Chunk,再看Asset這一列,產生了兩個bundle,還有一個.map文件。

這就是Chunk和Bundle的區別,Chunk是過程當中的代碼塊,Bundle是結果的代碼塊。app

查看Webpack源碼,發現有一個Chunk.js,點進去看:

/**
 * A Chunk is a unit of encapsulation for Modules.
 * Chunks are "rendered" into bundles that get emitted when the build completes.
 */
class Chunk {
}
複製代碼

裏面有一個Chunk類,這說明類Webpack在運行中,會生成Chunk對象,也能證實Chunk是過程當中的代碼塊。

Chunk類上面的兩句註釋:一個Chunk是一些模塊的封裝單元。Chunk在構建完成就呈現爲bundle。

產生Chunk的三種途徑

  1. entry入口
  2. 異步加載模塊
  3. 代碼分割(code spliting)

entry產生Chunk

entry的配置有三種方式:

傳遞一個字符串

entry: './src/js/main.js',
複製代碼

這種狀況只會產生一個Chunk。(這裏只說entry對Chunk的影響,不涉及代碼分割)

傳遞數組

entry: ['./src/js/main.js','./src/js/other.js'],

複製代碼

這種狀況也只會產生一個Chunk。Webpack會將數組裏的源代碼,最終都打包到一個Bundle裏,緣由就是隻生成了一個Chunk.

傳遞對象

entry: {
    main: './src/js/main.js',
    other: './src/js/other.js'
},
output: {
    // path: __dirname + "/public",
    // filename:'bundle.js'
    // 以上2行會報錯 

    path: __dirname + "/public",//打包後的文件存放的地方
    filename: "[name].js", //打包後輸出文件的文件名

}

複製代碼

對象中一個字段就會產生一個Chunk,因此在output中filename直接寫死名稱,會報錯。由於上面的配置,產生了兩個Chunk,最終會生成兩個Bundle,一個名稱確定不夠用了。須要用[name]變量來利用entry下的字段名稱,做爲生成Bundle們的名稱。

這裏面entry的key,也被用來看成它對應的Chunk的名稱,上面傳遞一個字符串和傳遞數組兩種方式,沒有key,也會默認給生成的Chunk一個main的名稱。

異步產生Chunk

除了入口文件會影響Chunk,異步加載的模塊,也須要生成Chunk。

{
    entry: {
        "index": "pages/index.jsx"
    },
    output: {
         filename: "[name].min.js",
        chunkFilename: "[name].min.js"
    }
}
const myModel = r => require.ensure([], () => r(require('./myVue.vue')), 'myModel')
複製代碼

這個時候chunkFilename字段就派上用場了,爲異步加載的Chunk命名。

代碼分割產生Chunk

咱們來分析一下,下面代碼會產生幾個Chunk,其中main.js文件和two.js文件,都引用了同一個greeter.js文件。main.js中使用了react。

module.exports = {
  entry: {
    main: __dirname + "/app/main.js",
    other: __dirname + "/app/two.js",
  },
  output: {
    path: __dirname + "/public",//打包後的文件存放的地方
    filename: "[name].js", //打包後輸出文件的文件名
    chunkFilename: '[name].js',
  },

  optimization: {
    runtimeChunk: "single",
    splitChunks: {
      cacheGroups: {
        commons: {
          chunks: "initial",
          minChunks: 2,
          maxInitialRequests: 5, // The default limit is too small to showcase the effect
          minSize: 0 // This is example is too small to create commons chunks
        },
        vendor: {
          test: /node_modules/,
          chunks: "initial",
          name: "vendor",
          priority: 10,
          enforce: true
        }

      },
    }
  }
}

複製代碼

答案是5個,兩個入口分別產生一個, runtimeChunk: "single"會將Webpack在瀏覽器端運行時須要的代碼單獨抽離到一個文件,commons下的配置會產生一個Chunk,vendor下的配置會產生一個Chunk。以下圖。

image

結束語

今天的研究就到這裏。

可以在看Webpack的配置的時候,分辨出這樣的配置能生成幾個Chunk,Webpack就算是入門了,後面理解它的其餘概念,會容易不少。

相關文章
相關標籤/搜索