mirror of https://github.com/webpack/webpack.git
add `minRemainingSize` option for splitChunks to ensure leftover chunks from splitting have a minimum size
defaults to `minSize` of cache group defaults to global option when not specified global option defaults to zero in development
This commit is contained in:
parent
0c39719729
commit
92f8c36ca2
|
@ -975,6 +975,10 @@ export interface OptimizationSplitChunksOptions {
|
|||
* Minimum number of times a module has to be duplicated until it's considered for splitting
|
||||
*/
|
||||
minChunks?: number;
|
||||
/**
|
||||
* Minimal size for the chunks the stay after moving the modules to a new chunk
|
||||
*/
|
||||
minRemainingSize?: OptimizationSplitChunksSizes;
|
||||
/**
|
||||
* Minimal size for the created chunks
|
||||
*/
|
||||
|
@ -1035,6 +1039,10 @@ export interface OptimizationSplitChunksCacheGroup {
|
|||
* Minimum number of times a module has to be duplicated until it's considered for splitting
|
||||
*/
|
||||
minChunks?: number;
|
||||
/**
|
||||
* Minimal size for the chunks the stay after moving the modules to a new chunk
|
||||
*/
|
||||
minRemainingSize?: OptimizationSplitChunksSizes;
|
||||
/**
|
||||
* Minimal size for the created chunk
|
||||
*/
|
||||
|
|
|
@ -283,6 +283,9 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
|
|||
this.set("optimization.splitChunks.minSize", "make", options => {
|
||||
return isProductionLikeMode(options) ? 30000 : 10000;
|
||||
});
|
||||
this.set("optimization.splitChunks.minRemainingSize", "make", options => {
|
||||
return options.mode === "development" ? 0 : undefined;
|
||||
});
|
||||
this.set("optimization.splitChunks.maxAsyncRequests", "make", options => {
|
||||
return isProductionLikeMode(options) ? 6 : Infinity;
|
||||
});
|
||||
|
|
|
@ -54,6 +54,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
|
|||
* @property {ChunkFilterFunction=} chunksFilter
|
||||
* @property {boolean=} enforce
|
||||
* @property {SplitChunksSizes} minSize
|
||||
* @property {SplitChunksSizes} minRemainingSize
|
||||
* @property {SplitChunksSizes} maxAsyncSize
|
||||
* @property {SplitChunksSizes} maxInitialSize
|
||||
* @property {number=} minChunks
|
||||
|
@ -73,6 +74,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
|
|||
* @property {ChunkFilterFunction=} chunksFilter
|
||||
* @property {boolean=} enforce
|
||||
* @property {SplitChunksSizes} minSize
|
||||
* @property {SplitChunksSizes} minRemainingSize
|
||||
* @property {SplitChunksSizes} minSizeForMaxSize
|
||||
* @property {SplitChunksSizes} maxAsyncSize
|
||||
* @property {SplitChunksSizes} maxInitialSize
|
||||
|
@ -118,6 +120,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
|
|||
* @typedef {Object} SplitChunksOptions
|
||||
* @property {ChunkFilterFunction} chunksFilter
|
||||
* @property {SplitChunksSizes} minSize
|
||||
* @property {SplitChunksSizes} minRemainingSize
|
||||
* @property {SplitChunksSizes} maxInitialSize
|
||||
* @property {SplitChunksSizes} maxAsyncSize
|
||||
* @property {number} minChunks
|
||||
|
@ -250,6 +253,17 @@ const mergeSizes = (...sizes) => {
|
|||
return Object.assign({}, ...sizes.map(normalizeSizes).reverse());
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {SplitChunksSizes} sizes the sizes
|
||||
* @returns {boolean} true, if there are sizes > 0
|
||||
*/
|
||||
const hasNonZeroSizes = sizes => {
|
||||
for (const key of Object.keys(sizes)) {
|
||||
if (sizes[key] > 0) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {SplitChunksSizes} a first sizes
|
||||
* @param {SplitChunksSizes} b second sizes
|
||||
|
@ -279,12 +293,12 @@ const combineSizes = (a, b, combine) => {
|
|||
/**
|
||||
* @param {SplitChunksSizes} sizes the sizes
|
||||
* @param {SplitChunksSizes} minSize the min sizes
|
||||
* @returns {boolean} true if sizes are below `minSize`
|
||||
* @returns {boolean} true if there are sizes and all existing sizes are at least `minSize`
|
||||
*/
|
||||
const checkMinSize = (sizes, minSize) => {
|
||||
for (const key of Object.keys(minSize)) {
|
||||
const size = sizes[key];
|
||||
if (size === undefined) return false;
|
||||
if (size === undefined || size === 0) continue;
|
||||
if (size < minSize[key]) return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -453,6 +467,7 @@ const createCacheGroupSource = options => {
|
|||
chunksFilter: normalizeChunksFilter(options.chunks),
|
||||
enforce: options.enforce,
|
||||
minSize: normalizeSizes(options.minSize),
|
||||
minRemainingSize: mergeSizes(options.minRemainingSize, options.minSize),
|
||||
maxAsyncSize: mergeSizes(options.maxAsyncSize, options.maxSize),
|
||||
maxInitialSize: mergeSizes(options.maxInitialSize, options.maxSize),
|
||||
minChunks: options.minChunks,
|
||||
|
@ -476,8 +491,9 @@ module.exports = class SplitChunksPlugin {
|
|||
this.options = {
|
||||
chunksFilter: normalizeChunksFilter(options.chunks || "all"),
|
||||
minSize: normalizeSizes(options.minSize),
|
||||
maxAsyncSize: normalizeSizes(options.maxAsyncSize || options.maxSize),
|
||||
maxInitialSize: normalizeSizes(options.maxInitialSize || options.maxSize),
|
||||
minRemainingSize: mergeSizes(options.minRemainingSize, options.minSize),
|
||||
maxAsyncSize: mergeSizes(options.maxAsyncSize, options.maxSize),
|
||||
maxInitialSize: mergeSizes(options.maxInitialSize, options.maxSize),
|
||||
minChunks: options.minChunks || 1,
|
||||
maxAsyncRequests: options.maxAsyncRequests || 1,
|
||||
maxInitialRequests: options.maxInitialRequests || 1,
|
||||
|
@ -700,7 +716,9 @@ module.exports = class SplitChunksPlugin {
|
|||
),
|
||||
cacheGroup,
|
||||
name,
|
||||
validateSize: Object.keys(cacheGroup.minSize).length > 0,
|
||||
validateSize:
|
||||
hasNonZeroSizes(cacheGroup.minSize) ||
|
||||
hasNonZeroSizes(cacheGroup.minRemainingSize),
|
||||
sizes: {},
|
||||
chunks: new Set(),
|
||||
reuseableChunks: new Set(),
|
||||
|
@ -756,6 +774,12 @@ module.exports = class SplitChunksPlugin {
|
|||
cacheGroupSource.minSize,
|
||||
cacheGroupSource.enforce ? undefined : this.options.minSize
|
||||
),
|
||||
minRemainingSize: mergeSizes(
|
||||
cacheGroupSource.minRemainingSize,
|
||||
cacheGroupSource.enforce
|
||||
? undefined
|
||||
: this.options.minRemainingSize
|
||||
),
|
||||
minSizeForMaxSize: mergeSizes(
|
||||
cacheGroupSource.minSize,
|
||||
this.options.minSize
|
||||
|
@ -954,12 +978,38 @@ module.exports = class SplitChunksPlugin {
|
|||
});
|
||||
}
|
||||
|
||||
validChunks = validChunks.filter(chunk => {
|
||||
for (const module of item.modules) {
|
||||
if (chunk.containsModule(module)) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (hasNonZeroSizes(item.cacheGroup.minRemainingSize)) {
|
||||
validChunks = validChunks.filter(chunk => {
|
||||
let chunkSizes = chunkGraph.getChunkModulesSizes(chunk);
|
||||
let containsModule = false;
|
||||
|
||||
// early check for remaining size
|
||||
if (!checkMinSize(chunkSizes, item.cacheGroup.minRemainingSize))
|
||||
return false;
|
||||
|
||||
chunkSizes = Object.assign({}, chunkSizes);
|
||||
for (const module of item.modules) {
|
||||
if (chunkGraph.isModuleInChunk(module, chunk)) {
|
||||
containsModule = true;
|
||||
for (const type of module.getSourceTypes()) {
|
||||
chunkSizes[type] -= module.size(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
containsModule &&
|
||||
checkMinSize(chunkSizes, item.cacheGroup.minRemainingSize)
|
||||
);
|
||||
});
|
||||
} else {
|
||||
validChunks = validChunks.filter(chunk => {
|
||||
for (const module of item.modules) {
|
||||
if (chunkGraph.isModuleInChunk(module, chunk)) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (validChunks.length < usedChunks.length) {
|
||||
if (isReused) validChunks.push(newChunk);
|
||||
|
|
|
@ -657,6 +657,14 @@
|
|||
"type": "number",
|
||||
"minimum": 1
|
||||
},
|
||||
"minRemainingSize": {
|
||||
"description": "Minimal size for the chunks the stay after moving the modules to a new chunk",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/OptimizationSplitChunksSizes"
|
||||
}
|
||||
]
|
||||
},
|
||||
"minSize": {
|
||||
"description": "Minimal size for the created chunk",
|
||||
"oneOf": [
|
||||
|
@ -865,6 +873,14 @@
|
|||
"type": "number",
|
||||
"minimum": 1
|
||||
},
|
||||
"minRemainingSize": {
|
||||
"description": "Minimal size for the chunks the stay after moving the modules to a new chunk",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/OptimizationSplitChunksSizes"
|
||||
}
|
||||
]
|
||||
},
|
||||
"minSize": {
|
||||
"description": "Minimal size for the created chunks",
|
||||
"oneOf": [
|
||||
|
|
|
@ -297,9 +297,17 @@ Child vendors:
|
|||
+ 3 hidden dependent modules
|
||||
Child multiple-vendors:
|
||||
Entrypoint main = multiple-vendors/main.js
|
||||
Entrypoint a = multiple-vendors/282.js multiple-vendors/954.js multiple-vendors/767.js multiple-vendors/a.js
|
||||
Entrypoint b = multiple-vendors/282.js multiple-vendors/954.js multiple-vendors/767.js multiple-vendors/b.js
|
||||
Entrypoint c = multiple-vendors/282.js multiple-vendors/769.js multiple-vendors/767.js multiple-vendors/c.js
|
||||
Entrypoint a = multiple-vendors/libs-x.js multiple-vendors/954.js multiple-vendors/767.js multiple-vendors/a.js
|
||||
Entrypoint b = multiple-vendors/libs-x.js multiple-vendors/954.js multiple-vendors/767.js multiple-vendors/b.js
|
||||
Entrypoint c = multiple-vendors/libs-x.js multiple-vendors/769.js multiple-vendors/767.js multiple-vendors/c.js
|
||||
chunk {119} multiple-vendors/libs-x.js (libs-x) 20 bytes [initial] [rendered] split chunk (cache group: libs) (name: libs-x)
|
||||
> ./a [10] ./index.js 1:0-47
|
||||
> ./b [10] ./index.js 2:0-47
|
||||
> ./c [10] ./index.js 3:0-47
|
||||
> ./a a
|
||||
> ./b b
|
||||
> ./c c
|
||||
[282] ./node_modules/x.js 20 bytes {119} [built]
|
||||
chunk {128} multiple-vendors/b.js (b) 92 bytes (javascript) 2.55 KiB (runtime) [entry] [rendered]
|
||||
> ./b b
|
||||
[996] ./b.js 72 bytes {128} {334} [built]
|
||||
|
@ -308,18 +316,10 @@ Child multiple-vendors:
|
|||
chunk {137} multiple-vendors/async-g.js (async-g) 34 bytes [rendered]
|
||||
> ./g ./a.js 6:0-47
|
||||
[785] ./g.js 34 bytes {137} [built]
|
||||
chunk {179} multiple-vendors/main.js (main) 147 bytes (javascript) 4.6 KiB (runtime) [entry] [rendered]
|
||||
chunk {179} multiple-vendors/main.js (main) 147 bytes (javascript) 4.61 KiB (runtime) [entry] [rendered]
|
||||
> ./ main
|
||||
[10] ./index.js 147 bytes {179} [built]
|
||||
+ 7 hidden root modules
|
||||
chunk {282} multiple-vendors/282.js 20 bytes [initial] [rendered] split chunk (cache group: vendors)
|
||||
> ./a [10] ./index.js 1:0-47
|
||||
> ./b [10] ./index.js 2:0-47
|
||||
> ./c [10] ./index.js 3:0-47
|
||||
> ./a a
|
||||
> ./b b
|
||||
> ./c c
|
||||
[282] ./node_modules/x.js 20 bytes {282} [built]
|
||||
chunk {334} multiple-vendors/async-b.js (async-b) 72 bytes [rendered]
|
||||
> ./b [10] ./index.js 2:0-47
|
||||
[996] ./b.js 72 bytes {128} {334} [built]
|
||||
|
@ -1539,15 +1539,15 @@ exports[`StatsTestCases should print correct stats for named-chunk-groups 1`] =
|
|||
> ./c [10] ./index.js 3:0-47
|
||||
[282] ./node_modules/x.js 20 bytes {216} [built]
|
||||
[954] ./node_modules/y.js 20 bytes {216} [built]
|
||||
chunk {334} async-b.js (async-b) 40 bytes [rendered]
|
||||
chunk {334} async-b.js (async-b) 175 bytes [rendered]
|
||||
> ./b [10] ./index.js 2:0-47
|
||||
[996] ./b.js 40 bytes {334} [built]
|
||||
[996] ./b.js 175 bytes {334} [built]
|
||||
chunk {383} async-c.js (async-c) 45 bytes [rendered]
|
||||
> ./c [10] ./index.js 3:0-47
|
||||
[460] ./c.js 45 bytes {383} [built]
|
||||
chunk {794} async-a.js (async-a) 40 bytes [rendered]
|
||||
chunk {794} async-a.js (async-a) 175 bytes [rendered]
|
||||
> ./a [10] ./index.js 1:0-47
|
||||
[847] ./a.js 40 bytes {794} [built]
|
||||
[847] ./a.js 175 bytes {794} [built]
|
||||
Child
|
||||
Entrypoint main = main.js
|
||||
Chunk Group async-a = 52.js async-a.js
|
||||
|
@ -1565,15 +1565,15 @@ Child
|
|||
> ./c [10] ./index.js 3:0-47
|
||||
[282] ./node_modules/x.js 20 bytes {216} [built]
|
||||
[954] ./node_modules/y.js 20 bytes {216} [built]
|
||||
chunk {334} async-b.js (async-b) 40 bytes [rendered]
|
||||
chunk {334} async-b.js (async-b) 175 bytes [rendered]
|
||||
> ./b [10] ./index.js 2:0-47
|
||||
[996] ./b.js 40 bytes {334} [built]
|
||||
[996] ./b.js 175 bytes {334} [built]
|
||||
chunk {383} async-c.js (async-c) 45 bytes [rendered]
|
||||
> ./c [10] ./index.js 3:0-47
|
||||
[460] ./c.js 45 bytes {383} [built]
|
||||
chunk {794} async-a.js (async-a) 40 bytes [rendered]
|
||||
chunk {794} async-a.js (async-a) 175 bytes [rendered]
|
||||
> ./a [10] ./index.js 1:0-47
|
||||
[847] ./a.js 40 bytes {794} [built]"
|
||||
[847] ./a.js 175 bytes {794} [built]"
|
||||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for named-chunks-plugin 1`] = `
|
||||
|
@ -3002,6 +3002,28 @@ chunk {786} a.js (a) 12 bytes (javascript) 2.53 KiB (runtime) ={282}= [entry] [r
|
|||
+ 2 hidden root modules"
|
||||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for split-chunks-keep-remaining-size 1`] = `
|
||||
"Entrypoint main = default/main.js
|
||||
chunk {52} default/52.js 102 bytes <{179}> ={383}= ={794}= [rendered] split chunk (cache group: default)
|
||||
> ./a [10] ./index.js 1:0-47
|
||||
> ./c [10] ./index.js 3:0-47
|
||||
[52] ./shared.js 102 bytes {52} {334} [built]
|
||||
chunk {179} default/main.js (main) 147 bytes (javascript) 4.57 KiB (runtime) >{52}< >{334}< >{383}< >{794}< [entry] [rendered]
|
||||
> ./ main
|
||||
[10] ./index.js 147 bytes {179} [built]
|
||||
+ 7 hidden root modules
|
||||
chunk {334} default/async-b.js (async-b) 141 bytes <{179}> [rendered]
|
||||
> ./b [10] ./index.js 2:0-47
|
||||
[996] ./b.js 39 bytes {334} [built]
|
||||
+ 1 hidden dependent module
|
||||
chunk {383} default/async-c.js (async-c) 142 bytes <{179}> ={52}= [rendered]
|
||||
> ./c [10] ./index.js 3:0-47
|
||||
[460] ./c.js 142 bytes {383} [built]
|
||||
chunk {794} default/async-a.js (async-a) 142 bytes <{179}> ={52}= [rendered]
|
||||
> ./a [10] ./index.js 1:0-47
|
||||
[847] ./a.js 142 bytes {794} [built]"
|
||||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for split-chunks-max-size 1`] = `
|
||||
"Child production:
|
||||
Entrypoint main = prod-869.js prod-410.js prod-main-10f51d07.js prod-main-3c98d7c3.js prod-main-6bb16544.js prod-main-1df31ce3.js prod-main-2f7dcf2e.js prod-main-e7c5ace7.js prod-main-5cfff2c6.js prod-main-1443e336.js prod-main-77a8c116.js prod-main-89a43a0f.js prod-main-12217e1d.js
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import "./shared";
|
||||
|
||||
export default "a";
|
||||
|
||||
// content content content content content content content content
|
||||
// content content content content content content content content
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import "./shared";
|
||||
|
||||
export default "b";
|
||||
|
||||
// content content content content content content content content
|
||||
// content content content content content content content content
|
||||
|
|
|
@ -19,7 +19,8 @@ module.exports = {
|
|||
},
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
minSize: 100
|
||||
minSize: 100,
|
||||
minRemainingSize: 0
|
||||
}
|
||||
},
|
||||
stats
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import "./shared";
|
||||
export default "a";
|
||||
|
||||
// content content content content content content
|
||||
// content content content content content content
|
|
@ -0,0 +1,2 @@
|
|||
import "./shared";
|
||||
export default "b";
|
|
@ -0,0 +1,5 @@
|
|||
import "./shared";
|
||||
export default "a";
|
||||
|
||||
// content content content content content content
|
||||
// content content content content content content
|
|
@ -0,0 +1,3 @@
|
|||
import(/* webpackChunkName: "async-a" */ "./a");
|
||||
import(/* webpackChunkName: "async-b" */ "./b");
|
||||
import(/* webpackChunkName: "async-c" */ "./c");
|
|
@ -0,0 +1,2 @@
|
|||
// content content content content content content
|
||||
// content content content content content content
|
|
@ -0,0 +1,26 @@
|
|||
const stats = {
|
||||
hash: false,
|
||||
timings: false,
|
||||
builtAt: false,
|
||||
assets: false,
|
||||
chunks: true,
|
||||
chunkRelations: true,
|
||||
chunkOrigins: true,
|
||||
entrypoints: true,
|
||||
modules: false
|
||||
};
|
||||
module.exports = {
|
||||
mode: "production",
|
||||
entry: {
|
||||
main: "./"
|
||||
},
|
||||
output: {
|
||||
filename: "default/[name].js"
|
||||
},
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
minSize: 100
|
||||
}
|
||||
},
|
||||
stats
|
||||
};
|
|
@ -19,7 +19,8 @@ module.exports = {
|
|||
},
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
minSize: 80
|
||||
minSize: 80,
|
||||
minRemainingSize: 0
|
||||
}
|
||||
},
|
||||
stats
|
||||
|
|
Loading…
Reference in New Issue