demo08 關於SplitChunksPlugin

1.SplitChunksPlugin 介紹

從 webpack4 開始,用 SplitChunksPlugin 插件替換了 CommonsChunkPlugin 插件。 相對於 CommonsChunkPlugin ,SplitChunksPlugin 的使用更加方便和清晰。javascript

SplitChunksPlugin 是 webpack4 內置的開箱即用的代碼塊分離插件,webpack4 會根據你配置好 optimization.splitChunks 規則,進行代碼分割,打包成不一樣的代碼塊。這樣的好處在於避免代碼重複引用,減小代碼體積,按需加載,從而使瀏覽器資源加載速度快,而且減小服務器的壓力和帶寬。html

SplitChunksPlugin 文檔:www.webpackjs.com/plugins/spl…java

2.splitChunks參數配置

  • chunks (默認是async) :initialasyncall
  • minSize (默認是30000):新代碼塊最小體積(壓縮以前),單位:字節(b)
  • minChunks(默認是1):代碼塊至少被引用的次數
  • maxInitialRequests (默認是3):入口處的最大並行請求數
  • maxAsyncRequests (默認是5):按需加載時最大的並行請求數
  • test (默認全部模塊): 匹配須要處理的模塊, 能夠傳的值類型: RegExp、String和Function
  • automaticNameDelimiter (默認是'~'): 打包分隔符
  • priority:緩存組打包的前後優先級

屬性優先級 minSize > maxSize > maxAsyncRequests > maxInitialRequestwebpack

這裏重要介紹一下 chunks 的三個屬性 initialasyncallgit

  • async 只對對動態(異步)導入的模塊進行分離
  • initial 對全部模塊進行分離,若是一個模塊既被異步引用,也被同部引用,那麼會生成兩個包
  • all 對全部模塊進行分離,若是一個模塊既被異步引用,也被同部引用,那麼只會生成一個共享包

具體能夠參考這篇文章: Webpack 4 Mysterious SplitChunks Plugingithub

3.安裝相關依賴

經過 html-webpack-plugin 自動生成 index.htmlweb

npm install -D html-webpack-plugin
npm install -D webpack // html-webpack-plugin 依賴於 webpack
複製代碼

3.目錄結構

// `--` 表明目錄, `-` 表明文件
  --demo08
    --src
      -app1.js
      -app2.js
      -module1.js
      -module2.js
      -module3.js
    -index.html
    -webpack.config.js
複製代碼

src/module1.jsnpm

export const module1 = 'module1';
複製代碼

src/module2.js瀏覽器

export const module2 = 'module2';
複製代碼

src/module3.js緩存

export const module3 = 'module3';
複製代碼

src/app1.js

import { module1 } from './module1';
import { module2 } from './module2';

// module1 module2 屬於同步加載
console.log('app1: ', module1);
console.log('app1: ', module2);

// 經過require.ensure對module3.js進行加載調用(此寫法在ts模式支持)
setTimeout(() => {
  require.ensure(
    [],
    function () {
      const module3 = require("./module3");
      console.log('app1: ', module3.module3);
    },
    "module3"
  );
}, 3000);

// // 異步加載的另外一種寫法(此寫法在ts模式下不支持)
// setTimeout(() => {
// import(/* webpackChunkName: 'module3'*/ "./module3").then(function (module3) {
// console.log(module3.module3);
// });
// }, 3000);
複製代碼

src/app2.js

import { module1 } from './module1';
import { module2 } from './module2';
import { module3 } from './module3';

// module1 module2 module3 都屬於同步加載(注意對比app1.js)
console.log('app2: ', module1);
console.log('app2: ', module2);
console.log('app2: ', module3);
複製代碼

4.編寫 webpack 配置文件

webpack.config.js

const path = require("path");
module.exports = {
  mode: 'production' || 'development',
  entry: {
    app1: "./src/app1.js",
    app2: "./src/app2.js"
  },
  output: {
    publicPath: __dirname + "/dist/", // 打包後資源文件的引用會基於此路徑
    path: path.resolve(__dirname, "dist"), // 打包後的輸出目錄
    filename: "[name].bundle.js",
    chunkFilename: "[name].chunk.js"
  },
  optimization: {
    // runtimeChunk: "single", // 使用single模式,能夠避免每個包都包含webpack的運行文件
    splitChunks: {
      cacheGroups: {
        modules: {
          chunks: "async" || "initial" || "all", // 三選一
          minChunks: 1, // 代碼塊至少被引用的次數
          maxInitialRequests: 3, // 設置最大的請求數
          minSize: 0, // 設置每一個chunk最小的大小,只有大於這個值,纔會被打包進一個chunk
          automaticNameDelimiter: '~'
        }
      }
    }
  }
};
複製代碼

5.執行打包命令

(默認你已經安裝了全局 webpack 以及 webpack-cli )

webpack
複製代碼

打包成功後,結果輸出在 demo08 的dist目錄下

在瀏覽器運行 dist/index.html,打開控制檯能夠觀察異步加載模塊的效果。

6.調試參數並驗證輸出結果

這裏能夠經過修改以上參數(好比 chunks , minChunks , minSize)的值來查看不一樣的輸出結果。

如上 webpack.config.js 配置文件,設置 minSize0 ,以及 minChunks1 以確保知足一個新塊的條件。

當設置 chunksasync

webpack只對異步加載的模塊進行分離,因此輸出結果爲:

app1.bundle.js
app2.bundle.js
modules~module3.chunk.js
複製代碼

(注意以上例子中有兩個入口文件 app1.js app2.js)

app1.js相關:

app1.bundle.js ( app1 主模塊,而且包含 module1.js 和 module2.js)
modules~module3.chunk.js
複製代碼

app2.js相關:

app2.bundle.js ( app2 主模塊,而且包含 module1.js、module2.js 和 module3.js)
複製代碼

當設置 chunksinitial

webpack對全部模塊進行分離,若是一個模塊既被異步引用,也被同部引用,那麼會生成兩個包,因此輸出結果爲:

app1.bundle.js
app2.bundle.js
module3.chunk.js
modules~app1.chunk.js
modules~app1~app2.chunk.js
modules~app2.chunk.js
複製代碼

app1.js相關:

app1.bundle.js (app1主模塊)
module3.chunk.js (包含 module3.js 異步加載模塊)
modules~app1.chunk.js (包含app1獨有的模塊: 這裏暫時沒有)
modules~app1~app2.chunk.js (包含 module1.js 和 module2.js)
複製代碼

app2.js相關:

app2.bundle.js (app2主模塊)
modules~app2.chunk.js (包含app2獨有的模塊: 這裏是module3.js)
modules~app1~app2.chunk.js (包含 module1.js 和 module2.js)
複製代碼

當設置 chunksall

webpack對全部模塊進行分離,若是一個模塊既被異步引用,也被同部引用,那麼只會生成一個共享包,因此輸出結果爲:

app1.bundle.js
app2.bundle.js
modules~app1.chunk.js
modules~app1~app2.chunk.js
modules~app2~module3.chunk.js
複製代碼

app1.js相關:

app1.bundle.js ( app1 主模塊)
modules~app1.chunk.js (包含 app1 獨有的模塊: 這裏暫時沒有)
modules~app1~app2.chunk.js (包含 module1.js 和 module2.js)
modules~app2~module3.chunk.js (包含 module3.js 模塊,雖然名字沒有 app1 ,可是能夠經過測試知道,app1 是依賴此模塊的,好比把此模塊刪除,而後在 index.html 中引入上面三個文件,查看控制檯就能知道 app1 依賴此模塊)
複製代碼

app2.js相關:

app2.bundle.js ( app2 主模塊)
modules~app1~app2.chunk.js (包含 module1.js 和 module2.js)
modules~app2~module3.chunk.js (包含 module3.js )
複製代碼

7.bundle vs chunk

不知你注意到沒有,以上打包結果中,app1 的主模塊(app1.bundle.js)和app2的主模塊(app2.bundle.js)的文件名包含的是 bundle,而其餘模塊包含的是 chunk。

bundle 代表該代碼塊包含有 webpack 運行時 的代碼。而 chunk 則沒有。 那你可能會問,這樣 app1.bundle.js 和 app2.bundle.js 就包含了一樣的 webpack 運行時代碼,能夠把這份 webpack 運行時的代碼單獨分離出來做爲一個單獨的塊嗎? 答案是能夠的。

在 webpack.config.js 配置文件中添加如下屬性便可:

runtimeChunk: "single"
複製代碼

這樣在以上 chunks 爲 all 的示例中,輸出的結果爲:

app1.chunk.js
app2.chunk.js
modules~app1.chunk.js
modules~app1~app2.chunk.js
modules~app2~module3.chunk.js
runtime.bundle.js ( webpack 運行時模塊)
複製代碼

8.源碼地址

demo 代碼地址: github.com/SimpleCodeC…

倉庫代碼地址(及目錄): github.com/SimpleCodeC…

參考文檔:

Webpack 4 Mysterious SplitChunks

SplitChunksPlugin官方文檔

相關文章
相關標籤/搜索