Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add splitChunks.minSizeReduction #14516

Merged
merged 1 commit into from Oct 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions declarations/WebpackOptions.d.ts
Expand Up @@ -1751,6 +1751,10 @@ export interface OptimizationSplitChunksOptions {
* Minimal size for the created chunk.
*/
minSize?: OptimizationSplitChunksSizes;
/**
* Minimum size reduction due to the created chunk.
*/
minSizeReduction?: OptimizationSplitChunksSizes;
};
/**
* Sets the template for the filename for created chunks.
Expand Down Expand Up @@ -1797,6 +1801,10 @@ export interface OptimizationSplitChunksOptions {
* Minimal size for the created chunks.
*/
minSize?: OptimizationSplitChunksSizes;
/**
* Minimum size reduction due to the created chunk.
*/
minSizeReduction?: OptimizationSplitChunksSizes;
/**
* Give chunks created a name (chunks with equal name are merged).
*/
Expand Down Expand Up @@ -1877,6 +1885,10 @@ export interface OptimizationSplitChunksCacheGroup {
* Minimal size for the created chunk.
*/
minSize?: OptimizationSplitChunksSizes;
/**
* Minimum size reduction due to the created chunk.
*/
minSizeReduction?: OptimizationSplitChunksSizes;
/**
* Give chunks for this cache group a name (chunks with equal name are merged).
*/
Expand Down
50 changes: 49 additions & 1 deletion lib/optimize/SplitChunksPlugin.js
Expand Up @@ -59,6 +59,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
* @property {ChunkFilterFunction=} chunksFilter
* @property {boolean=} enforce
* @property {SplitChunksSizes} minSize
* @property {SplitChunksSizes} minSizeReduction
* @property {SplitChunksSizes} minRemainingSize
* @property {SplitChunksSizes} enforceSizeThreshold
* @property {SplitChunksSizes} maxAsyncSize
Expand All @@ -80,6 +81,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
* @property {GetName=} getName
* @property {ChunkFilterFunction=} chunksFilter
* @property {SplitChunksSizes} minSize
* @property {SplitChunksSizes} minSizeReduction
* @property {SplitChunksSizes} minRemainingSize
* @property {SplitChunksSizes} enforceSizeThreshold
* @property {SplitChunksSizes} maxAsyncSize
Expand Down Expand Up @@ -132,6 +134,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
* @property {ChunkFilterFunction} chunksFilter
* @property {string[]} defaultSizeTypes
* @property {SplitChunksSizes} minSize
* @property {SplitChunksSizes} minSizeReduction
* @property {SplitChunksSizes} minRemainingSize
* @property {SplitChunksSizes} enforceSizeThreshold
* @property {SplitChunksSizes} maxInitialSize
Expand Down Expand Up @@ -336,6 +339,21 @@ const checkMinSize = (sizes, minSize) => {
return true;
};

/**
* @param {SplitChunksSizes} sizes the sizes
* @param {SplitChunksSizes} minSizeReduction the min sizes
* @param {number} chunkCount number of chunks
* @returns {boolean} true if there are sizes and all existing sizes are at least `minSizeReduction`
*/
const checkMinSizeReduction = (sizes, minSizeReduction, chunkCount) => {
for (const key of Object.keys(minSizeReduction)) {
const size = sizes[key];
if (size === undefined || size === 0) continue;
if (size * chunkCount < minSizeReduction[key]) return false;
}
return true;
};

/**
* @param {SplitChunksSizes} sizes the sizes
* @param {SplitChunksSizes} minSize the min sizes
Expand Down Expand Up @@ -548,6 +566,10 @@ const checkModuleLayer = (test, module) => {
*/
const createCacheGroupSource = (options, key, defaultSizeTypes) => {
const minSize = normalizeSizes(options.minSize, defaultSizeTypes);
const minSizeReduction = normalizeSizes(
options.minSizeReduction,
defaultSizeTypes
);
const maxSize = normalizeSizes(options.maxSize, defaultSizeTypes);
return {
key,
Expand All @@ -556,6 +578,7 @@ const createCacheGroupSource = (options, key, defaultSizeTypes) => {
chunksFilter: normalizeChunksFilter(options.chunks),
enforce: options.enforce,
minSize,
minSizeReduction,
minRemainingSize: mergeSizes(
normalizeSizes(options.minRemainingSize, defaultSizeTypes),
minSize
Expand Down Expand Up @@ -594,13 +617,18 @@ module.exports = class SplitChunksPlugin {
];
const fallbackCacheGroup = options.fallbackCacheGroup || {};
const minSize = normalizeSizes(options.minSize, defaultSizeTypes);
const minSizeReduction = normalizeSizes(
options.minSizeReduction,
defaultSizeTypes
);
const maxSize = normalizeSizes(options.maxSize, defaultSizeTypes);

/** @type {SplitChunksOptions} */
this.options = {
chunksFilter: normalizeChunksFilter(options.chunks || "all"),
defaultSizeTypes,
minSize,
minSizeReduction,
minRemainingSize: mergeSizes(
normalizeSizes(options.minRemainingSize, defaultSizeTypes),
minSize
Expand Down Expand Up @@ -668,6 +696,10 @@ module.exports = class SplitChunksPlugin {
cacheGroupSource.minSize,
cacheGroupSource.enforce ? undefined : this.options.minSize
);
const minSizeReduction = mergeSizes(
cacheGroupSource.minSizeReduction,
cacheGroupSource.enforce ? undefined : this.options.minSizeReduction
);
const minRemainingSize = mergeSizes(
cacheGroupSource.minRemainingSize,
cacheGroupSource.enforce ? undefined : this.options.minRemainingSize
Expand All @@ -681,6 +713,7 @@ module.exports = class SplitChunksPlugin {
priority: cacheGroupSource.priority || 0,
chunksFilter: cacheGroupSource.chunksFilter || this.options.chunksFilter,
minSize,
minSizeReduction,
minRemainingSize,
enforceSizeThreshold,
maxAsyncSize: mergeSizes(
Expand Down Expand Up @@ -1244,6 +1277,14 @@ module.exports = class SplitChunksPlugin {
for (const [key, info] of chunksInfoMap) {
if (removeMinSizeViolatingModules(info)) {
chunksInfoMap.delete(key);
} else if (
!checkMinSizeReduction(
info.sizes,
info.cacheGroup.minSizeReduction,
info.chunks.size
)
) {
chunksInfoMap.delete(key);
}
}

Expand Down Expand Up @@ -1531,7 +1572,14 @@ module.exports = class SplitChunksPlugin {
chunksInfoMap.delete(key);
continue;
}
if (removeMinSizeViolatingModules(info)) {
if (
removeMinSizeViolatingModules(info) ||
!checkMinSizeReduction(
info.sizes,
info.cacheGroup.minSizeReduction,
info.chunks.size
)
) {
chunksInfoMap.delete(key);
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion schemas/WebpackOptions.check.js

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions schemas/WebpackOptions.json
Expand Up @@ -2458,6 +2458,14 @@
}
]
},
"minSizeReduction": {
"description": "Minimum size reduction due to the created chunk.",
"oneOf": [
{
"$ref": "#/definitions/OptimizationSplitChunksSizes"
}
]
},
"name": {
"description": "Give chunks for this cache group a name (chunks with equal name are merged).",
"anyOf": [
Expand Down Expand Up @@ -2654,6 +2662,14 @@
"$ref": "#/definitions/OptimizationSplitChunksSizes"
}
]
},
"minSizeReduction": {
"description": "Minimum size reduction due to the created chunk.",
"oneOf": [
{
"$ref": "#/definitions/OptimizationSplitChunksSizes"
}
]
}
}
},
Expand Down Expand Up @@ -2730,6 +2746,14 @@
}
]
},
"minSizeReduction": {
"description": "Minimum size reduction due to the created chunk.",
"oneOf": [
{
"$ref": "#/definitions/OptimizationSplitChunksSizes"
}
]
},
"name": {
"description": "Give chunks created a name (chunks with equal name are merged).",
"anyOf": [
Expand Down
34 changes: 17 additions & 17 deletions test/Validation.test.js
Expand Up @@ -453,18 +453,18 @@ describe("Validation", () => {
},
msg =>
expect(msg).toMatchInlineSnapshot(`
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
- configuration.optimization.splitChunks.cacheGroups should not be object { test, … }.
-> Using the cacheGroup shorthand syntax with a cache group named 'test' is a potential config error
Did you intent to define a cache group with a test instead?
cacheGroups: {
<name>: {
test: ...
}
}.
object { <key>: false | RegExp | string | function | object { automaticNameDelimiter?, chunks?, enforce?, enforceSizeThreshold?, filename?, idHint?, layer?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, name?, priority?, reuseExistingChunk?, test?, type?, usedExports? } }
-> Assign modules to a cache group (modules from different cache groups are tried to keep in separate chunks, default categories: 'default', 'defaultVendors')."
`)
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
- configuration.optimization.splitChunks.cacheGroups should not be object { test, … }.
-> Using the cacheGroup shorthand syntax with a cache group named 'test' is a potential config error
Did you intent to define a cache group with a test instead?
cacheGroups: {
<name>: {
test: ...
}
}.
object { <key>: false | RegExp | string | function | object { automaticNameDelimiter?, chunks?, enforce?, enforceSizeThreshold?, filename?, idHint?, layer?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, minSizeReduction?, name?, priority?, reuseExistingChunk?, test?, type?, usedExports? } }
-> Assign modules to a cache group (modules from different cache groups are tried to keep in separate chunks, default categories: 'default', 'defaultVendors')."
`)
);

createTestCase(
Expand Down Expand Up @@ -661,11 +661,11 @@ describe("Validation", () => {
},
msg =>
expect(msg).toMatchInlineSnapshot(`
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
- configuration.optimization.splitChunks has an unknown property 'automaticNamePrefix'. These properties are valid:
object { automaticNameDelimiter?, cacheGroups?, chunks?, defaultSizeTypes?, enforceSizeThreshold?, fallbackCacheGroup?, filename?, hidePathInfo?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, name?, usedExports? }
-> Options object for splitting chunks into smaller chunks."
`)
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
- configuration.optimization.splitChunks has an unknown property 'automaticNamePrefix'. These properties are valid:
object { automaticNameDelimiter?, cacheGroups?, chunks?, defaultSizeTypes?, enforceSizeThreshold?, fallbackCacheGroup?, filename?, hidePathInfo?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, minSizeReduction?, name?, usedExports? }
-> Options object for splitting chunks into smaller chunks."
`)
);
});
});
26 changes: 26 additions & 0 deletions test/__snapshots__/Cli.test.js.snap
Expand Up @@ -4446,6 +4446,19 @@ Object {
"multiple": false,
"simpleType": "number",
},
"optimization-split-chunks-fallback-cache-group-min-size-reduction": Object {
"configs": Array [
Object {
"description": "Size of the javascript part of the chunk.",
"multiple": false,
"path": "optimization.splitChunks.fallbackCacheGroup.minSizeReduction",
"type": "number",
},
],
"description": "Size of the javascript part of the chunk.",
"multiple": false,
"simpleType": "number",
},
"optimization-split-chunks-filename": Object {
"configs": Array [
Object {
Expand Down Expand Up @@ -4576,6 +4589,19 @@ Object {
"multiple": false,
"simpleType": "number",
},
"optimization-split-chunks-min-size-reduction": Object {
"configs": Array [
Object {
"description": "Size of the javascript part of the chunk.",
"multiple": false,
"path": "optimization.splitChunks.minSizeReduction",
"type": "number",
},
],
"description": "Size of the javascript part of the chunk.",
"multiple": false,
"simpleType": "number",
},
"optimization-split-chunks-name": Object {
"configs": Array [
Object {
Expand Down
31 changes: 31 additions & 0 deletions test/__snapshots__/StatsTestCases.basictest.js.snap
Expand Up @@ -4292,6 +4292,37 @@ enforce-min-size:
enforce-min-size (webpack x.x.x) compiled successfully"
`;

exports[`StatsTestCases should print correct stats for split-chunks-min-size-reduction 1`] = `
"Entrypoint main 11.5 KiB = default/main.js
chunk (runtime: main) default/async-d.js (async-d) 50 bytes <{179}> ={821}= [rendered]
> ./d ./index.js 4:0-47
./d.js 50 bytes [built] [code generated]
chunk (runtime: main) default/main.js (main) 245 bytes (javascript) 6.68 KiB (runtime) >{31}< >{334}< >{383}< >{449}< >{794}< >{821}< [entry] [rendered]
> ./ main
runtime modules 6.68 KiB 9 modules
./index.js 245 bytes [built] [code generated]
chunk (runtime: main) default/async-b.js (async-b) 176 bytes <{179}> [rendered]
> ./b ./index.js 2:0-47
./b.js 50 bytes [built] [code generated]
./node_modules/shared.js?1 126 bytes [dependent] [built] [code generated]
chunk (runtime: main) default/async-c.js (async-c) 50 bytes <{179}> ={821}= [rendered]
> ./c ./index.js 3:0-47
./c.js 50 bytes [built] [code generated]
chunk (runtime: main) default/async-e.js (async-e) 50 bytes <{179}> ={821}= [rendered]
> ./e ./index.js 5:0-47
./e.js 50 bytes [built] [code generated]
chunk (runtime: main) default/async-a.js (async-a) 176 bytes <{179}> [rendered]
> ./a ./index.js 1:0-47
./a.js 50 bytes [built] [code generated]
./node_modules/shared.js?1 126 bytes [dependent] [built] [code generated]
chunk (runtime: main) default/821.js (id hint: vendors) 126 bytes <{179}> ={31}= ={383}= ={449}= [rendered] split chunk (cache group: defaultVendors)
> ./c ./index.js 3:0-47
> ./d ./index.js 4:0-47
> ./e ./index.js 5:0-47
./node_modules/shared.js?2 126 bytes [built] [code generated]
webpack x.x.x compiled successfully"
`;

exports[`StatsTestCases should print correct stats for split-chunks-prefer-bigger-splits 1`] = `
"Entrypoint main 11.2 KiB = default/main.js
chunk (runtime: main) default/118.js 150 bytes <{179}> ={334}= ={383}= [rendered] split chunk (cache group: default)
Expand Down
2 changes: 2 additions & 0 deletions test/statsCases/split-chunks-min-size-reduction/a.js
@@ -0,0 +1,2 @@
import s from "shared?1";
export default "a" + s;
2 changes: 2 additions & 0 deletions test/statsCases/split-chunks-min-size-reduction/b.js
@@ -0,0 +1,2 @@
import s from "shared?1";
export default "b" + s;
2 changes: 2 additions & 0 deletions test/statsCases/split-chunks-min-size-reduction/c.js
@@ -0,0 +1,2 @@
import s from "shared?2";
export default "c" + s;
2 changes: 2 additions & 0 deletions test/statsCases/split-chunks-min-size-reduction/d.js
@@ -0,0 +1,2 @@
import s from "shared?2";
export default "c" + s;
2 changes: 2 additions & 0 deletions test/statsCases/split-chunks-min-size-reduction/e.js
@@ -0,0 +1,2 @@
import s from "shared?2";
export default "c" + s;
5 changes: 5 additions & 0 deletions test/statsCases/split-chunks-min-size-reduction/index.js
@@ -0,0 +1,5 @@
import(/* webpackChunkName: "async-a" */ "./a");
import(/* webpackChunkName: "async-b" */ "./b");
import(/* webpackChunkName: "async-c" */ "./c");
import(/* webpackChunkName: "async-d" */ "./d");
import(/* webpackChunkName: "async-e" */ "./e");

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions test/statsCases/split-chunks-min-size-reduction/webpack.config.js
@@ -0,0 +1,30 @@
const stats = {
hash: false,
timings: false,
builtAt: false,
assets: false,
chunks: true,
chunkRelations: true,
chunkModules: true,
dependentModules: true,
chunkOrigins: true,
entrypoints: true,
modules: false
};
/** @type {import("../../../").Configuration} */
module.exports = {
mode: "production",
entry: {
main: "./"
},
output: {
filename: "default/[name].js"
},
optimization: {
splitChunks: {
minSize: 0,
minSizeReduction: 300
}
},
stats
};