原本,區塊(以及在其中匯入的模組)透過內部 webpack 圖表中的父子關係連接。CommonsChunkPlugin
用於避免它們之間重複的依賴關係,但無法進行進一步的最佳化。
自 webpack v4 開始,CommonsChunkPlugin
已被移除,改用 optimization.splitChunks
。
開箱即用的 SplitChunksPlugin
應能順利運作於大多數使用者。
預設值僅影響依需求區塊,因為變更初始區塊會影響 HTML 檔案應包含的腳本標籤,以執行專案。
Webpack 會根據下列條件自動分割區塊
node_modules
資料夾在嘗試滿足最後兩個條件時,較大的區塊會優先。
Webpack 提供一組選項,讓開發人員可以更進一步控制此功能。
此組態物件表示 SplitChunksPlugin
的預設行為。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async',
minSize: 20000,
minRemainingSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};
字串 = '~'
預設情況下,webpack 會使用區塊的來源和名稱來產生名稱(例如 vendors~main.js
)。此選項讓您可以指定用於產生名稱的分隔符號。
字串 = 'async'
函式 (chunk)
正規表示式
這表示將選取哪些區塊進行最佳化。當提供字串時,有效值為 all
、async
和 initial
。提供 all
可能特別有效,因為這表示區塊甚至可以在非同步區塊之間共用。
請注意,它也套用於後備快取群組 (splitChunks.fallbackCacheGroup.chunks
)。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
// include all types of chunks
chunks: 'all',
},
},
};
或者,您可以提供一個函式以取得更多控制權。傳回值將表示是否包含每個區塊。
module.exports = {
//...
optimization: {
splitChunks: {
chunks(chunk) {
// exclude `my-excluded-chunk`
return chunk.name !== 'my-excluded-chunk';
},
},
},
};
如果您使用的是 webpack 版本 5.86.0 或更新版本,您也可以傳遞正規表示法
module.exports = {
//...
optimization: {
splitChunks: {
chunks: /foo/,
},
},
};
數字 = 30
隨選載入時的並行要求最大數目。
數字 = 30
進入點的並行要求最大數目。
[字串] = ['javascript', 'unknown']
當數字用於大小時,設定所使用的類型大小。
數字 = 1
在分割之前,模組必須在區塊之間共用的最少次數。
布林值
在為由 maxSize 分割的部分建立名稱時,防止公開路徑資訊。
數字 = 20000
{ [索引: 字串]: 數字 }
要產生區塊的最小位元組大小。
數字
{ [index: 字串]: 數字 }
要產生區塊,主區塊 (套件) 的最小大小縮減,以位元組為單位。表示如果將主區塊 (套件) 的大小縮減的位元組數小於指定數量,即使符合 splitChunks.minSize
值,也不會分割,也不會產生區塊。
splitChunks.cacheGroups.{cacheGroup}.enforceSizeThreshold
數字 = 50000
強制分割的大小臨界值,並忽略其他限制 (minRemainingSize、maxAsyncRequests、maxInitialRequests)。
splitChunks.cacheGroups.{cacheGroup}.minRemainingSize
數字 = 0
splitChunks.minRemainingSize
選項在 webpack 5 中引入,用於避免零大小模組,方法是確保分割後剩餘區塊的最小大小高於限制。在 「開發」模式 中預設為 0
。在其他情況下,splitChunks.minRemainingSize
預設為 splitChunks.minSize
的值,因此不需要手動指定,除非需要深入控制的罕見情況。
splitChunks.cacheGroups.{cacheGroup}.layer
RegExp
字串
函式
依據模組層級將模組指定至快取群組。
數字 = 0
使用 maxSize
(全域 optimization.splitChunks.maxSize
每個快取群組 optimization.splitChunks.cacheGroups[x].maxSize
或預設快取群組 optimization.splitChunks.fallbackCacheGroup.maxSize
)告知 webpack 嘗試將大於 maxSize
位元組的區塊分割成較小的部分。部分將至少為 minSize
(緊接在 maxSize
之後)的大小。演算法具有確定性,而模組的變更僅會產生區域影響。因此,在使用長期快取時可用,且不需要記錄。maxSize
僅為提示,且當模組大於 maxSize
或分割會違反 minSize
時可能會遭到違反。
當區塊已具有名稱時,每個部分都會從該名稱衍生出一個新名稱。根據 optimization.splitChunks.hidePathInfo
的值,它會新增一個衍生自第一個模組名稱或其雜湊的鍵。
maxSize
選項旨在與 HTTP/2 和長期快取搭配使用。它會增加要求次數以改善快取。它也可以用於縮小檔案大小以加快重建速度。
數字
與 maxSize
相同,maxAsyncSize
可以套用於全域 (splitChunks.maxAsyncSize
)、快取群組 (splitChunks.cacheGroups.{cacheGroup}.maxAsyncSize
) 或備用快取群組 (splitChunks.fallbackCacheGroup.maxAsyncSize
)。
maxAsyncSize
與 maxSize
的差異在於 maxAsyncSize
僅會影響依需求載入的區塊。
數字
與 maxSize
相同,maxInitialSize
可以套用於全域 (splitChunks.maxInitialSize
)、快取群組 (splitChunks.cacheGroups.{cacheGroup}.maxInitialSize
) 或備用快取群組 (splitChunks.fallbackCacheGroup.maxInitialSize
)。
maxInitialSize
與 maxSize
的差異在於 maxInitialSize
僅會影響初始載入的區塊。
boolean = false
function (module, chunks, cacheGroupKey) => string
string
每個快取群組也可用:splitChunks.cacheGroups.{cacheGroup}.name
。
分割區塊的名稱。提供 false
會保留區塊的相同名稱,因此不會不必要地變更名稱。這是建議用於生產建置的值。
提供字串或函式可讓您使用自訂名稱。指定字串或總是傳回相同字串的函式會將所有常見模組和廠商合併至單一區塊。這可能會導致較大的初始下載量並降低頁面載入速度。
如果您選擇指定函式,您可能會發現 chunk.name
屬性(其中 chunk
是 chunks
陣列的元素)在為區塊選擇名稱時特別有用。
如果 splitChunks.name
與進入點名稱相符,進入點將會移除。
main.js
import _ from 'lodash';
console.log(_.join(['Hello', 'webpack'], ' '));
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
// cacheGroupKey here is `commons` as the key of the cacheGroup
name(module, chunks, cacheGroupKey) {
const moduleFileName = module
.identifier()
.split('/')
.reduceRight((item) => item);
const allChunksNames = chunks.map((item) => item.name).join('~');
return `${cacheGroupKey}-${allChunksNames}-${moduleFileName}`;
},
chunks: 'all',
},
},
},
},
};
使用下列 splitChunks
設定執行 webpack 也會輸出與下一個名稱共用的群組區塊:commons-main-lodash.js.e7519d2bb8777058fa27.js
(雜湊作為實際世界輸出的範例)。
splitChunks.cacheGroups{cacheGroup}.usedExports
布林值 = true
找出模組使用哪些輸出,以扭曲輸出名稱、略過未使用的輸出,並產生更有效率的程式碼。當其為 true
時:分析每個執行時間使用的輸出,當其為 "global"
時:分析所有執行時間合併的輸出。
快取群組可以繼承和/或覆寫 splitChunks.*
中的任何選項;但 test
、priority
和 reuseExistingChunk
只能在快取群組層級中設定。若要停用任何預設快取群組,請將它們設為 false
。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
default: false,
},
},
},
};
splitChunks.cacheGroups.{cacheGroup}.priority
number = -20
模組可以屬於多個快取群組。最佳化會偏好優先度較高的快取群組。預設群組具有負優先度,以允許自訂群組取得較高的優先度(自訂群組的預設值為 0
)。
splitChunks.cacheGroups.{cacheGroup}.reuseExistingChunk
布林值 = true
如果目前的區塊包含已從主套件分割出來的模組,它會被重複使用,而不是產生新的區塊。這可能會影響區塊的結果檔名。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
reuseExistingChunk: true,
},
},
},
},
};
splitChunks.cacheGroups.{cacheGroup}.type
function
RegExp
string
允許依據模組類型將模組指定給快取群組。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
json: {
type: 'json',
},
},
},
},
};
splitChunks.cacheGroups.{cacheGroup}.test
function (module, { chunkGraph, moduleGraph }) => boolean
RegExp
string
控制由這個快取群組選取的模組。省略它會選取所有模組。它可以符合絕對模組資源路徑或區塊名稱。當符合區塊名稱時,區塊中的所有模組都會被選取。
提供一個函式給 {cacheGroup}.test
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
svgGroup: {
test(module) {
// `module.resource` contains the absolute path of the file on disk.
// Note the usage of `path.sep` instead of / or \, for cross-platform compatibility.
const path = require('path');
return (
module.resource &&
module.resource.endsWith('.svg') &&
module.resource.includes(`${path.sep}cacheable_svgs${path.sep}`)
);
},
},
byModuleTypeGroup: {
test(module) {
return module.type === 'javascript/auto';
},
},
},
},
},
};
為了查看 module
和 chunks
物件中有哪些資訊可用,您可以在 callback 中放置 debugger;
陳述式。然後 以偵錯模式執行您的 webpack 建置 以在 Chromium DevTools 中檢查參數。
提供一個 RegExp
給 {cacheGroup}.test
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
// Note the usage of `[\\/]` as a path separator for cross-platform compatibility.
test: /[\\/]node_modules[\\/]|vendor[\\/]analytics_provider|vendor[\\/]other_lib/,
},
},
},
},
};
splitChunks.cacheGroups.{cacheGroup}.filename
字串
函式 (pathData, assetInfo) => 字串
允許在初次分割時覆寫檔名。所有在 output.filename
中可用的佔位符在此處也可用。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
filename: '[name].bundle.js',
},
},
},
},
};
作為函式
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
filename: (pathData) => {
// Use pathData object for generating filename string based on your requirements
return `${pathData.chunk.name}-bundle.js`;
},
},
},
},
},
};
透過提供路徑作為檔名前綴,可以建立資料夾結構:'js/vendor/bundle.js'
。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
filename: 'js/[name]/bundle.js',
},
},
},
},
};
splitChunks.cacheGroups.{cacheGroup}.enforce
布林值 = false
指示 webpack 忽略 splitChunks.minSize
、splitChunks.minChunks
、splitChunks.maxAsyncRequests
和 splitChunks.maxInitialRequests
選項,並永遠為此快取群組建立分割區塊。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
enforce: true,
},
},
},
},
};
splitChunks.cacheGroups.{cacheGroup}.idHint
字串
設定分割區塊 ID 的提示。它會新增到分割區塊的檔名中。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
defaultVendors: {
idHint: 'vendors',
},
},
},
},
};
// index.js
import('./a'); // dynamic import
// a.js
import 'react';
//...
結果:會建立一個包含 react
的獨立分割區塊。在匯入呼叫時,此分割區塊會與包含 ./a
的原始分割區塊並行載入。
原因
node_modules
的模組react
大於 30kb背後的理由是什麼?react
可能不會像應用程式程式碼那樣經常變更。透過將其移至一個獨立的區塊,此區塊可以與應用程式程式碼分開快取(假設您使用區塊雜湊、記錄、快取控制或其他長期快取方法)。
// entry.js
// dynamic imports
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
及其所有相依項目的獨立區塊。在匯入呼叫時,此區塊會與原始區塊並行載入。
原因
helpers
大於 30kb將 helpers
的內容放入每個區塊會導致其程式碼被下載兩次。透過使用獨立區塊,這只會發生一次。我們支付額外要求的成本,這可以視為權衡。這就是為什麼有 30kb 的最小大小。
建立一個 commons
區塊,其中包含所有進入點之間共用的程式碼。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: 'commons',
chunks: 'initial',
minChunks: 2,
},
},
},
},
};
建立一個 vendors
區塊,其中包含整個應用程式中所有來自 node_modules
的程式碼。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
};
建立一個 自訂供應商
區塊,其中包含由 RegExp
匹配的特定 node_modules
套件。
webpack.config.js
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'vendor',
chunks: 'all',
},
},
},
},
};