webpack4系列教程(六):使用SplitChunksPlugin分割代碼

傳送門:

webpack4系列教程(一):初識webpack
webpack4系列教程(二):創建項目,打包第一個JS文件
webpack4系列教程(三):自動生成項目中的HTML文件
webpack4系列教程(四):處理項目中的資源文件(一)
webpack4系列教程(五):處理項目中的資源文件(二)

1. SplitChunksPlugin的概念

起初,chunks(代碼塊)和導入他們中的模塊通過webpack內部的父子關係圖連接.在webpack3中,通過CommonsChunkPlugin來避免他們之間的依賴重複。而在webpack4中CommonsChunkPlugin被移除,取而代之的是 optimization.splitChunks 和 optimization.runtimeChunk 配置項,下面展示它們將如何工作。

在默認情況下,SplitChunksPlugin 僅僅影響按需加載的代碼塊,因爲更改初始塊會影響HTML文件應包含的腳本標記以運行項目。

webpack將根據以下條件自動拆分代碼塊:

  • 會被共享的代碼塊或者 node_mudules 文件夾中的代碼塊
  • 體積大於30KB的代碼塊(在gz壓縮前)
  • 按需加載代碼塊時的並行請求數量不超過5個
  • 加載初始頁面時的並行請求數量不超過3個

舉例1:

// index.js

// 動態加載 a.js
import('./a')
// a.js
import 'vue'

// ...

打包之後的結果會創建一個包含 vue 的獨立代碼塊,當包含 a.js 的原始代碼塊被調用時,這個獨立代碼塊會並行請求進來。

原因:

  • vue 來自 node_modules 文件夾
  • vue 體積超過30KB
  • 導入調用時的並行請求數爲2
  • 不影響頁面初始加載

我們這樣做的原因是因爲,vue代碼並不像你的業務代碼那樣經常變動,把它單獨提取出來就可以和你的業務代碼分開緩存,極大的提高效率。

舉例2:

// entry.js

import("./a");
import("./b");
// a.js
import "./helpers"; // helpers is 40kb in size

// ...
// b.js
import "./helpers";
import "./more-helpers"; // more-helpers is also 40kb in size

// ...

結果:將創建一個單獨的塊,其中包含./helpers它的所有依賴項。在導入調用時,此塊與原始塊並行加載。

原因:

  • 條件1:helpers 是共享塊
  • 條件2:helpers大於30kb
  • 條件3:導入調用的並行請求數爲2
  • 條件4:不影響初始頁面加載時的請求

2. SplitChunksPlugin的默認配置

以下是SplitChunksPlugin的默認配置:

splitChunks: {
    chunks: "async",
    minSize: 30000, // 模塊的最小體積
    minChunks: 1, // 模塊的最小被引用次數
    maxAsyncRequests: 5, // 按需加載的最大並行請求數
    maxInitialRequests: 3, // 一個入口最大並行請求數
    automaticNameDelimiter: '~', // 文件名的連接符
    name: true,
    cacheGroups: { // 緩存組
        vendors: {
            test: /[\\/]node_modules[\\/]/,
            priority: -10
        },
        default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true
        }
    }
}

緩存組:

緩存組因該是SplitChunksPlugin中最有趣的功能了。在默認設置中,會將 node_mudules 文件夾中的模塊打包進一個叫 vendors的bundle中,所有引用超過兩次的模塊分配到 default bundle 中。更可以通過 priority 來設置優先級。

chunks:

chunks屬性用來選擇分割哪些代碼塊,可選值有:'all'(所有代碼塊),'async'(按需加載的代碼塊),'initial'(初始化代碼塊)。

3. 在項目中添加SplitChunksPlugin

爲了方便演示,我們先安裝兩個類庫: lodash 和 axios,

npm i lodash axios -S

修改 main.js,引入 lodash 和axios 並調用相應方法:

import Modal from './components/modal/modal'
import './assets/style/common.less'
import _ from 'lodash'
import axios from 'axios'
const App = function () {
  let div = document.createElement('div')
  div.setAttribute('id', 'app')
  document.body.appendChild(div)
  let dom = document.getElementById('app')
  let modal = new Modal()
  dom.innerHTML = modal.template({
    title: '標題',
    content: '內容',
    footer: '底部'
  })
}
const app = new App()
console.log(_.camelCase('Foo Bar'))
axios.get('aaa')

使用SplitChunksPlugin不需要安裝任何依賴,只需在 webpack.config.js 中的 config對象添加 optimization 屬性:

optimization: {
    splitChunks: {
      chunks: 'initial',
      automaticNameDelimiter: '.',
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: 1
        }
      }
    },
    runtimeChunk: {
      name: entrypoint => `manifest.${entrypoint.name}`
    }
  }

配置 runtimeChunk 會給每個入口添加一個只包含runtime的額外的代碼塊,name 的值也可以是字符串,不過這樣就會給每個入口添加相同的 runtime,配置爲函數時,返回當前的entry對象,即可分入口設置不同的runtime。

我們再安裝一個 webpack-bundle-analyzer,這個插件會清晰的展示出打包後的各個bundle所依賴的模塊:

npm i webpack-bundle-analyzer -D

引入:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

使用,在plugins數組中添加即可:

new BundleAnalyzerPlugin()

打包之後:

各個模塊依賴清晰可見,打開 dist/index.html可見我們的代碼順利運行:

以上就是SplitChunksPlugin的基本用法,更多高級的配置大家可以繼續鑽研(比如多入口應用)。


本人才疏學淺,不當之處歡迎批評指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章