Skip to content

Commit

Permalink
add splitChunks.minSizeReduction
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Oct 19, 2021
1 parent 4a23389 commit 3d3c65f
Show file tree
Hide file tree
Showing 16 changed files with 224 additions and 19 deletions.
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
};

0 comments on commit 3d3c65f

Please sign in to comment.