Merge pull request #11166 from webpack/http2/defaults

Http2 defaults for splitChunks
This commit is contained in:
Tobias Koppers 2020-07-13 14:56:46 +02:00 committed by GitHub
commit 020b8d6997
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 194 additions and 96 deletions

View File

@ -1372,6 +1372,10 @@ export interface OptimizationSplitChunksOptions {
chunks?: chunks?:
| ("initial" | "async" | "all") | ("initial" | "async" | "all")
| ((chunk: import("../lib/Chunk")) => boolean); | ((chunk: import("../lib/Chunk")) => boolean);
/**
* Size threshold at which splitting is enforced and other restrictions (minRemainingSize, maxAsyncRequests, maxInitialRequests) are ignored.
*/
enforceSizeThreshold?: OptimizationSplitChunksSizes;
/** /**
* Options for modules not selected by any other cache group. * Options for modules not selected by any other cache group.
*/ */
@ -1465,6 +1469,10 @@ export interface OptimizationSplitChunksCacheGroup {
* Ignore minimum size, minimum chunks and maximum requests and always create chunks for this cache group. * Ignore minimum size, minimum chunks and maximum requests and always create chunks for this cache group.
*/ */
enforce?: boolean; enforce?: boolean;
/**
* Size threshold at which splitting is enforced and other restrictions (minRemainingSize, maxAsyncRequests, maxInitialRequests) are ignored.
*/
enforceSizeThreshold?: OptimizationSplitChunksSizes;
/** /**
* Sets the template for the filename for created chunks. * Sets the template for the filename for created chunks.
*/ */

View File

@ -580,8 +580,9 @@ const applyOptimizationDefaults = (
D(splitChunks, "hidePathInfo", production); D(splitChunks, "hidePathInfo", production);
D(splitChunks, "chunks", "async"); D(splitChunks, "chunks", "async");
D(splitChunks, "minChunks", 1); D(splitChunks, "minChunks", 1);
F(splitChunks, "minSize", () => (production ? 30000 : 10000)); F(splitChunks, "minSize", () => (production ? 20000 : 10000));
F(splitChunks, "minRemainingSize", () => (development ? 0 : undefined)); F(splitChunks, "minRemainingSize", () => (development ? 0 : undefined));
F(splitChunks, "enforceSizeThreshold", () => (production ? 50000 : 30000));
F(splitChunks, "maxAsyncRequests", () => (production ? 30 : Infinity)); F(splitChunks, "maxAsyncRequests", () => (production ? 30 : Infinity));
F(splitChunks, "maxInitialRequests", () => (production ? 30 : Infinity)); F(splitChunks, "maxInitialRequests", () => (production ? 30 : Infinity));
D(splitChunks, "automaticNameDelimiter", "-"); D(splitChunks, "automaticNameDelimiter", "-");

View File

@ -58,6 +58,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
* @property {boolean=} enforce * @property {boolean=} enforce
* @property {SplitChunksSizes} minSize * @property {SplitChunksSizes} minSize
* @property {SplitChunksSizes} minRemainingSize * @property {SplitChunksSizes} minRemainingSize
* @property {SplitChunksSizes} enforceSizeThreshold
* @property {SplitChunksSizes} maxAsyncSize * @property {SplitChunksSizes} maxAsyncSize
* @property {SplitChunksSizes} maxInitialSize * @property {SplitChunksSizes} maxInitialSize
* @property {number=} minChunks * @property {number=} minChunks
@ -75,10 +76,9 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
* @property {number=} priority * @property {number=} priority
* @property {GetName=} getName * @property {GetName=} getName
* @property {ChunkFilterFunction=} chunksFilter * @property {ChunkFilterFunction=} chunksFilter
* @property {boolean=} enforce
* @property {SplitChunksSizes} minSize * @property {SplitChunksSizes} minSize
* @property {SplitChunksSizes} minRemainingSize * @property {SplitChunksSizes} minRemainingSize
* @property {SplitChunksSizes} minSizeForMaxSize * @property {SplitChunksSizes} enforceSizeThreshold
* @property {SplitChunksSizes} maxAsyncSize * @property {SplitChunksSizes} maxAsyncSize
* @property {SplitChunksSizes} maxInitialSize * @property {SplitChunksSizes} maxInitialSize
* @property {number=} minChunks * @property {number=} minChunks
@ -88,6 +88,10 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
* @property {string=} idHint * @property {string=} idHint
* @property {string} automaticNameDelimiter * @property {string} automaticNameDelimiter
* @property {boolean=} reuseExistingChunk * @property {boolean=} reuseExistingChunk
* @property {boolean} _validateSize
* @property {boolean} _validateRemainingSize
* @property {SplitChunksSizes} _minSizeForMaxSize
* @property {boolean} _conditionalEnforce
*/ */
/** /**
@ -124,6 +128,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
* @property {ChunkFilterFunction} chunksFilter * @property {ChunkFilterFunction} chunksFilter
* @property {SplitChunksSizes} minSize * @property {SplitChunksSizes} minSize
* @property {SplitChunksSizes} minRemainingSize * @property {SplitChunksSizes} minRemainingSize
* @property {SplitChunksSizes} enforceSizeThreshold
* @property {SplitChunksSizes} maxInitialSize * @property {SplitChunksSizes} maxInitialSize
* @property {SplitChunksSizes} maxAsyncSize * @property {SplitChunksSizes} maxAsyncSize
* @property {number} minChunks * @property {number} minChunks
@ -141,8 +146,8 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
* @typedef {Object} ChunksInfoItem * @typedef {Object} ChunksInfoItem
* @property {SortableSet<Module>} modules * @property {SortableSet<Module>} modules
* @property {CacheGroup} cacheGroup * @property {CacheGroup} cacheGroup
* @property {number} cacheGroupIndex
* @property {string} name * @property {string} name
* @property {boolean} validateSize
* @property {Record<string, number>} sizes * @property {Record<string, number>} sizes
* @property {Set<Chunk>} chunks * @property {Set<Chunk>} chunks
* @property {Set<Chunk>} reuseableChunks * @property {Set<Chunk>} reuseableChunks
@ -220,12 +225,15 @@ const compareEntries = (a, b) => {
const bSizeReduce = totalSize(b.sizes) * (b.chunks.size - 1); const bSizeReduce = totalSize(b.sizes) * (b.chunks.size - 1);
const diffSizeReduce = aSizeReduce - bSizeReduce; const diffSizeReduce = aSizeReduce - bSizeReduce;
if (diffSizeReduce) return diffSizeReduce; if (diffSizeReduce) return diffSizeReduce;
// 4. by number of modules (to be able to compare by identifier) // 4. by cache group index
const indexDiff = a.cacheGroupIndex - b.cacheGroupIndex;
if (indexDiff) return indexDiff;
// 5. by number of modules (to be able to compare by identifier)
const modulesA = a.modules; const modulesA = a.modules;
const modulesB = b.modules; const modulesB = b.modules;
const diff = modulesA.size - modulesB.size; const diff = modulesA.size - modulesB.size;
if (diff) return diff; if (diff) return diff;
// 5. by module identifiers // 6. by module identifiers
modulesA.sort(); modulesA.sort();
modulesB.sort(); modulesB.sort();
return compareModuleIterables(modulesA, modulesB); return compareModuleIterables(modulesA, modulesB);
@ -507,6 +515,7 @@ const createCacheGroupSource = (options, key) => {
enforce: options.enforce, enforce: options.enforce,
minSize: normalizeSizes(options.minSize), minSize: normalizeSizes(options.minSize),
minRemainingSize: mergeSizes(options.minRemainingSize, options.minSize), minRemainingSize: mergeSizes(options.minRemainingSize, options.minSize),
enforceSizeThreshold: normalizeSizes(options.enforceSizeThreshold),
maxAsyncSize: mergeSizes(options.maxAsyncSize, options.maxSize), maxAsyncSize: mergeSizes(options.maxAsyncSize, options.maxSize),
maxInitialSize: mergeSizes(options.maxInitialSize, options.maxSize), maxInitialSize: mergeSizes(options.maxInitialSize, options.maxSize),
minChunks: options.minChunks, minChunks: options.minChunks,
@ -531,6 +540,7 @@ module.exports = class SplitChunksPlugin {
chunksFilter: normalizeChunksFilter(options.chunks || "all"), chunksFilter: normalizeChunksFilter(options.chunks || "all"),
minSize: normalizeSizes(options.minSize), minSize: normalizeSizes(options.minSize),
minRemainingSize: mergeSizes(options.minRemainingSize, options.minSize), minRemainingSize: mergeSizes(options.minRemainingSize, options.minSize),
enforceSizeThreshold: normalizeSizes(options.enforceSizeThreshold),
maxAsyncSize: mergeSizes(options.maxAsyncSize, options.maxSize), maxAsyncSize: mergeSizes(options.maxAsyncSize, options.maxSize),
maxInitialSize: mergeSizes(options.maxInitialSize, options.maxSize), maxInitialSize: mergeSizes(options.maxInitialSize, options.maxSize),
minChunks: options.minChunks || 1, minChunks: options.minChunks || 1,
@ -714,6 +724,7 @@ module.exports = class SplitChunksPlugin {
/** /**
* @param {CacheGroup} cacheGroup the current cache group * @param {CacheGroup} cacheGroup the current cache group
* @param {number} cacheGroupIndex the index of the cache group of ordering
* @param {Chunk[]} selectedChunks chunks selected for this module * @param {Chunk[]} selectedChunks chunks selected for this module
* @param {bigint} selectedChunksKey a key of selectedChunks * @param {bigint} selectedChunksKey a key of selectedChunks
* @param {Module} module the current module * @param {Module} module the current module
@ -721,6 +732,7 @@ module.exports = class SplitChunksPlugin {
*/ */
const addModuleToChunksInfoMap = ( const addModuleToChunksInfoMap = (
cacheGroup, cacheGroup,
cacheGroupIndex,
selectedChunks, selectedChunks,
selectedChunksKey, selectedChunksKey,
module module
@ -771,10 +783,8 @@ module.exports = class SplitChunksPlugin {
compareModulesByIdentifier compareModulesByIdentifier
), ),
cacheGroup, cacheGroup,
cacheGroupIndex,
name, name,
validateSize:
hasNonZeroSizes(cacheGroup.minSize) ||
hasNonZeroSizes(cacheGroup.minRemainingSize),
sizes: {}, sizes: {},
chunks: new Set(), chunks: new Set(),
reuseableChunks: new Set(), reuseableChunks: new Set(),
@ -783,10 +793,8 @@ module.exports = class SplitChunksPlugin {
); );
} }
info.modules.add(module); info.modules.add(module);
if (info.validateSize) { for (const type of module.getSourceTypes()) {
for (const type of module.getSourceTypes()) { info.sizes[type] = (info.sizes[type] || 0) + module.size(type);
info.sizes[type] = (info.sizes[type] || 0) + module.size(type);
}
} }
if (!info.chunksKeys.has(selectedChunksKey)) { if (!info.chunksKeys.has(selectedChunksKey)) {
info.chunksKeys.add(selectedChunksKey); info.chunksKeys.add(selectedChunksKey);
@ -823,29 +831,35 @@ module.exports = class SplitChunksPlugin {
combinationsCache.set(chunksKey, combs); combinationsCache.set(chunksKey, combs);
} }
let cacheGroupIndex = 0;
for (const cacheGroupSource of cacheGroups) { for (const cacheGroupSource of cacheGroups) {
/** @type {CacheGroup} */ /** @type {CacheGroup} */
let cacheGroup = this._cacheGroupCache.get(cacheGroupSource); let cacheGroup = this._cacheGroupCache.get(cacheGroupSource);
if (cacheGroup === undefined) { if (cacheGroup === undefined) {
const minSize = mergeSizes(
cacheGroupSource.minSize,
cacheGroupSource.enforce ? undefined : this.options.minSize
);
const minRemainingSize = mergeSizes(
cacheGroupSource.minRemainingSize,
cacheGroupSource.enforce
? undefined
: this.options.minRemainingSize
);
const enforceSizeThreshold = mergeSizes(
cacheGroupSource.enforceSizeThreshold,
cacheGroupSource.enforce
? undefined
: this.options.enforceSizeThreshold
);
cacheGroup = { cacheGroup = {
key: cacheGroupSource.key, key: cacheGroupSource.key,
priority: cacheGroupSource.priority || 0, priority: cacheGroupSource.priority || 0,
chunksFilter: chunksFilter:
cacheGroupSource.chunksFilter || this.options.chunksFilter, cacheGroupSource.chunksFilter || this.options.chunksFilter,
minSize: mergeSizes( minSize,
cacheGroupSource.minSize, minRemainingSize,
cacheGroupSource.enforce ? undefined : this.options.minSize enforceSizeThreshold,
),
minRemainingSize: mergeSizes(
cacheGroupSource.minRemainingSize,
cacheGroupSource.enforce
? undefined
: this.options.minRemainingSize
),
minSizeForMaxSize: mergeSizes(
cacheGroupSource.minSize,
this.options.minSize
),
maxAsyncSize: mergeSizes( maxAsyncSize: mergeSizes(
cacheGroupSource.maxAsyncSize, cacheGroupSource.maxAsyncSize,
cacheGroupSource.enforce cacheGroupSource.enforce
@ -892,7 +906,14 @@ module.exports = class SplitChunksPlugin {
cacheGroupSource.idHint !== undefined cacheGroupSource.idHint !== undefined
? cacheGroupSource.idHint ? cacheGroupSource.idHint
: cacheGroupSource.key, : cacheGroupSource.key,
reuseExistingChunk: cacheGroupSource.reuseExistingChunk reuseExistingChunk: cacheGroupSource.reuseExistingChunk,
_validateSize: hasNonZeroSizes(minSize),
_validateRemainingSize: hasNonZeroSizes(minRemainingSize),
_minSizeForMaxSize: mergeSizes(
cacheGroupSource.minSize,
this.options.minSize
),
_conditionalEnforce: hasNonZeroSizes(enforceSizeThreshold)
}; };
} }
// For all combination of chunk selection // For all combination of chunk selection
@ -910,11 +931,13 @@ module.exports = class SplitChunksPlugin {
addModuleToChunksInfoMap( addModuleToChunksInfoMap(
cacheGroup, cacheGroup,
cacheGroupIndex,
selectedChunks, selectedChunks,
selectedChunksKey, selectedChunksKey,
module module
); );
} }
cacheGroupIndex++;
} }
} }
@ -923,13 +946,12 @@ module.exports = class SplitChunksPlugin {
logger.time("queue"); logger.time("queue");
// Filter items were size < minSize // Filter items were size < minSize
for (const pair of chunksInfoMap) { for (const [key, info] of chunksInfoMap) {
const info = pair[1];
if ( if (
info.validateSize && info.cacheGroup._validateSize &&
!checkMinSize(info.sizes, info.cacheGroup.minSize) !checkMinSize(info.sizes, info.cacheGroup.minSize)
) { ) {
chunksInfoMap.delete(pair[0]); chunksInfoMap.delete(key);
} }
} }
@ -1021,18 +1043,20 @@ module.exports = class SplitChunksPlugin {
// TODO check if this check is really needed, shouldn't chunks always be non-empty? // TODO check if this check is really needed, shouldn't chunks always be non-empty?
if (item.chunks.size === 0 && !isExistingChunk) continue; if (item.chunks.size === 0 && !isExistingChunk) continue;
const enforced =
item.cacheGroup._conditionalEnforce &&
checkMinSize(item.sizes, item.cacheGroup.enforceSizeThreshold);
const usedChunks = new Set(item.chunks);
// Check if maxRequests condition can be fulfilled // Check if maxRequests condition can be fulfilled
// TODO try to avoid creating a new array here
const usedChunks = Array.from(item.chunks);
let validChunks = usedChunks;
if ( if (
Number.isFinite(item.cacheGroup.maxInitialRequests) || !enforced &&
Number.isFinite(item.cacheGroup.maxAsyncRequests) (Number.isFinite(item.cacheGroup.maxInitialRequests) ||
Number.isFinite(item.cacheGroup.maxAsyncRequests))
) { ) {
validChunks = validChunks.filter(chunk => { for (const chunk of usedChunks) {
// respect max requests when not enforced // respect max requests
const maxRequests = chunk.isOnlyInitial() const maxRequests = chunk.isOnlyInitial()
? item.cacheGroup.maxInitialRequests ? item.cacheGroup.maxInitialRequests
: chunk.canBeInitial() : chunk.canBeInitial()
@ -1041,27 +1065,34 @@ module.exports = class SplitChunksPlugin {
item.cacheGroup.maxAsyncRequests item.cacheGroup.maxAsyncRequests
) )
: item.cacheGroup.maxAsyncRequests; : item.cacheGroup.maxAsyncRequests;
return ( if (
!isFinite(maxRequests) || getRequests(chunk) < maxRequests isFinite(maxRequests) &&
); getRequests(chunk) >= maxRequests
}); ) {
usedChunks.delete(chunk);
}
}
} }
validChunks = validChunks.filter(chunk => { outer: for (const chunk of usedChunks) {
for (const module of item.modules) { for (const module of item.modules) {
if (chunkGraph.isModuleInChunk(module, chunk)) return true; if (chunkGraph.isModuleInChunk(module, chunk)) continue outer;
} }
return false; usedChunks.delete(chunk);
}); }
if (validChunks.length < usedChunks.length) { // Were some (invalid) chunks removed from usedChunks?
if (isExistingChunk) validChunks.push(newChunk); // => readd all modules to the queue, as things could have been changed
if (validChunks.length >= item.cacheGroup.minChunks) { if (usedChunks.size < item.chunks.size) {
if (isExistingChunk) usedChunks.add(newChunk);
if (usedChunks.size >= item.cacheGroup.minChunks) {
const chunksArr = Array.from(usedChunks);
for (const module of item.modules) { for (const module of item.modules) {
addModuleToChunksInfoMap( addModuleToChunksInfoMap(
item.cacheGroup, item.cacheGroup,
validChunks, item.cacheGroupIndex,
getKey(validChunks), chunksArr,
getKey(usedChunks),
module module
); );
} }
@ -1071,13 +1102,19 @@ module.exports = class SplitChunksPlugin {
// Validate minRemainingSize constraint when a single chunk is left over // Validate minRemainingSize constraint when a single chunk is left over
if ( if (
validChunks.length === 1 && !enforced &&
hasNonZeroSizes(item.cacheGroup.minRemainingSize) item.cacheGroup._validateRemainingSize &&
usedChunks.size === 1
) { ) {
const chunk = validChunks[0]; const [chunk] = usedChunks;
const chunkSizes = { ...chunkGraph.getChunkModulesSizes(chunk) }; let chunkSizes = Object.create(null);
for (const key of Object.keys(item.sizes)) { for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
chunkSizes[key] -= item.sizes[key]; if (!item.modules.has(module)) {
for (const type of module.getSourceTypes()) {
chunkSizes[type] =
(chunkSizes[type] || 0) + module.size(type);
}
}
} }
if (!checkMinSize(chunkSizes, item.cacheGroup.minRemainingSize)) { if (!checkMinSize(chunkSizes, item.cacheGroup.minRemainingSize)) {
continue; continue;
@ -1148,7 +1185,7 @@ module.exports = class SplitChunksPlugin {
minSize: oldMaxSizeSettings minSize: oldMaxSizeSettings
? combineSizes( ? combineSizes(
oldMaxSizeSettings.minSize, oldMaxSizeSettings.minSize,
item.cacheGroup.minSizeForMaxSize, item.cacheGroup._minSizeForMaxSize,
Math.max Math.max
) )
: item.cacheGroup.minSize, : item.cacheGroup.minSize,
@ -1175,38 +1212,31 @@ module.exports = class SplitChunksPlugin {
// remove all modules from other entries and update size // remove all modules from other entries and update size
for (const [key, info] of chunksInfoMap) { for (const [key, info] of chunksInfoMap) {
if (isOverlap(info.chunks, item.chunks)) { if (isOverlap(info.chunks, usedChunks)) {
if (info.validateSize) { // update modules and total size
// update modules and total size // may remove it from the map when < minSize
// may remove it from the map when < minSize let updated = false;
let updated = false; for (const module of item.modules) {
for (const module of item.modules) { if (info.modules.has(module)) {
if (info.modules.has(module)) { // remove module
// remove module
info.modules.delete(module);
// update size
for (const key of module.getSourceTypes()) {
info.sizes[key] -= module.size(key);
}
updated = true;
}
}
if (updated) {
if (info.modules.size === 0) {
chunksInfoMap.delete(key);
continue;
}
if (!checkMinSize(info.sizes, info.cacheGroup.minSize)) {
chunksInfoMap.delete(key);
}
}
} else {
// only update the modules
for (const module of item.modules) {
info.modules.delete(module); info.modules.delete(module);
// update size
for (const key of module.getSourceTypes()) {
info.sizes[key] -= module.size(key);
}
updated = true;
} }
}
if (updated) {
if (info.modules.size === 0) { if (info.modules.size === 0) {
chunksInfoMap.delete(key); chunksInfoMap.delete(key);
continue;
}
if (
info.cacheGroup._validateSize &&
!checkMinSize(info.sizes, info.cacheGroup.minSize)
) {
chunksInfoMap.delete(key);
} }
} }
} }

View File

@ -1257,6 +1257,14 @@
"description": "Ignore minimum size, minimum chunks and maximum requests and always create chunks for this cache group.", "description": "Ignore minimum size, minimum chunks and maximum requests and always create chunks for this cache group.",
"type": "boolean" "type": "boolean"
}, },
"enforceSizeThreshold": {
"description": "Size threshold at which splitting is enforced and other restrictions (minRemainingSize, maxAsyncRequests, maxInitialRequests) are ignored.",
"oneOf": [
{
"$ref": "#/definitions/OptimizationSplitChunksSizes"
}
]
},
"filename": { "filename": {
"description": "Sets the template for the filename for created chunks.", "description": "Sets the template for the filename for created chunks.",
"anyOf": [ "anyOf": [
@ -1464,6 +1472,14 @@
} }
] ]
}, },
"enforceSizeThreshold": {
"description": "Size threshold at which splitting is enforced and other restrictions (minRemainingSize, maxAsyncRequests, maxInitialRequests) are ignored.",
"oneOf": [
{
"$ref": "#/definitions/OptimizationSplitChunksSizes"
}
]
},
"fallbackCacheGroup": { "fallbackCacheGroup": {
"description": "Options for modules not selected by any other cache group.", "description": "Options for modules not selected by any other cache group.",
"type": "object", "type": "object",

View File

@ -184,6 +184,7 @@ describe("Defaults", () => {
}, },
}, },
"chunks": "async", "chunks": "async",
"enforceSizeThreshold": 30000,
"hidePathInfo": false, "hidePathInfo": false,
"maxAsyncRequests": Infinity, "maxAsyncRequests": Infinity,
"maxInitialRequests": Infinity, "maxInitialRequests": Infinity,
@ -379,15 +380,17 @@ describe("Defaults", () => {
+ "noEmitOnErrors": true, + "noEmitOnErrors": true,
+ "nodeEnv": "production", + "nodeEnv": "production",
@@ ... @@ @@ ... @@
- "enforceSizeThreshold": 30000,
- "hidePathInfo": false, - "hidePathInfo": false,
- "maxAsyncRequests": Infinity, - "maxAsyncRequests": Infinity,
- "maxInitialRequests": Infinity, - "maxInitialRequests": Infinity,
+ "enforceSizeThreshold": 50000,
+ "hidePathInfo": true, + "hidePathInfo": true,
+ "maxAsyncRequests": 30, + "maxAsyncRequests": 30,
+ "maxInitialRequests": 30, + "maxInitialRequests": 30,
@@ ... @@ @@ ... @@
- "minSize": 10000, - "minSize": 10000,
+ "minSize": 30000, + "minSize": 20000,
@@ ... @@ @@ ... @@
- "usedExports": false, - "usedExports": false,
+ "usedExports": true, + "usedExports": true,
@ -432,15 +435,17 @@ describe("Defaults", () => {
+ "noEmitOnErrors": true, + "noEmitOnErrors": true,
+ "nodeEnv": "production", + "nodeEnv": "production",
@@ ... @@ @@ ... @@
- "enforceSizeThreshold": 30000,
- "hidePathInfo": false, - "hidePathInfo": false,
- "maxAsyncRequests": Infinity, - "maxAsyncRequests": Infinity,
- "maxInitialRequests": Infinity, - "maxInitialRequests": Infinity,
+ "enforceSizeThreshold": 50000,
+ "hidePathInfo": true, + "hidePathInfo": true,
+ "maxAsyncRequests": 30, + "maxAsyncRequests": 30,
+ "maxInitialRequests": 30, + "maxInitialRequests": 30,
@@ ... @@ @@ ... @@
- "minSize": 10000, - "minSize": 10000,
+ "minSize": 30000, + "minSize": 20000,
@@ ... @@ @@ ... @@
- "usedExports": false, - "usedExports": false,
+ "usedExports": true, + "usedExports": true,
@ -956,6 +961,7 @@ describe("Defaults", () => {
- }, - },
- }, - },
- "chunks": "async", - "chunks": "async",
- "enforceSizeThreshold": 30000,
- "hidePathInfo": false, - "hidePathInfo": false,
- "maxAsyncRequests": Infinity, - "maxAsyncRequests": Infinity,
- "maxInitialRequests": Infinity, - "maxInitialRequests": Infinity,

View File

@ -461,7 +461,7 @@ describe("Validation", () => {
test: ... test: ...
} }
}. }.
object { <key>: false | RegExp | string | function | object { automaticNameDelimiter?, chunks?, enforce?, filename?, idHint?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, name?, priority?, reuseExistingChunk?, test?, type? } } object { <key>: false | RegExp | string | function | object { automaticNameDelimiter?, chunks?, enforce?, enforceSizeThreshold?, filename?, idHint?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, name?, priority?, reuseExistingChunk?, test?, type? } }
-> Assign modules to a cache group (modules from different cache groups are tried to keep in separate chunks, default categories: 'default', 'defaultVendors')." -> Assign modules to a cache group (modules from different cache groups are tried to keep in separate chunks, default categories: 'default', 'defaultVendors')."
`) `)
); );
@ -715,7 +715,7 @@ describe("Validation", () => {
expect(msg).toMatchInlineSnapshot(` expect(msg).toMatchInlineSnapshot(`
"Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema. "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: - configuration.optimization.splitChunks has an unknown property 'automaticNamePrefix'. These properties are valid:
object { automaticNameDelimiter?, cacheGroups?, chunks?, fallbackCacheGroup?, filename?, hidePathInfo?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, name? } object { automaticNameDelimiter?, cacheGroups?, chunks?, enforceSizeThreshold?, fallbackCacheGroup?, filename?, hidePathInfo?, maxAsyncRequests?, maxAsyncSize?, maxInitialRequests?, maxInitialSize?, maxSize?, minChunks?, minRemainingSize?, minSize?, name? }
-> Options object for splitting chunks into smaller chunks." -> Options object for splitting chunks into smaller chunks."
`) `)
); );

View File

@ -1532,6 +1532,19 @@ Object {
"multiple": false, "multiple": false,
"simpleType": "string", "simpleType": "string",
}, },
"optimization-split-chunks-enforce-size-threshold": Object {
"configs": Array [
Object {
"description": "Size of the javascript part of the chunk.",
"multiple": false,
"path": "optimization.splitChunks.enforceSizeThreshold",
"type": "number",
},
],
"description": "Size of the javascript part of the chunk.",
"multiple": false,
"simpleType": "number",
},
"optimization-split-chunks-fallback-cache-group-automatic-name-delimiter": Object { "optimization-split-chunks-fallback-cache-group-automatic-name-delimiter": Object {
"configs": Array [ "configs": Array [
Object { Object {

View File

@ -3413,9 +3413,12 @@ chunk a.js (a) 12 bytes (javascript) 3.87 KiB (runtime) ={282}= [entry] [rendere
exports[`StatsTestCases should print correct stats for split-chunks-keep-remaining-size 1`] = ` exports[`StatsTestCases should print correct stats for split-chunks-keep-remaining-size 1`] = `
"Entrypoint main = default/main.js "Entrypoint main = default/main.js
chunk default/main.js (main) 147 bytes (javascript) 5.69 KiB (runtime) >{334}< >{383}< >{794}< >{821}< [entry] [rendered] chunk default/async-d.js (async-d) 58 bytes <{179}> ={782}= [rendered]
> ./d ./index.js 4:0-47
./d.js 58 bytes [built]
chunk default/main.js (main) 196 bytes (javascript) 5.7 KiB (runtime) >{31}< >{334}< >{383}< >{782}< >{794}< >{821}< [entry] [rendered]
> ./ main > ./ main
./index.js 147 bytes [built] ./index.js 196 bytes [built]
+ 9 hidden chunk modules + 9 hidden chunk modules
chunk default/async-b.js (async-b) 39 bytes <{179}> ={821}= [rendered] chunk default/async-b.js (async-b) 39 bytes <{179}> ={821}= [rendered]
> ./b ./index.js 2:0-47 > ./b ./index.js 2:0-47
@ -3423,6 +3426,10 @@ chunk default/async-b.js (async-b) 39 bytes <{179}> ={821}= [rendered]
chunk default/async-c.js (async-c) 39 bytes <{179}> ={821}= [rendered] chunk default/async-c.js (async-c) 39 bytes <{179}> ={821}= [rendered]
> ./c ./index.js 3:0-47 > ./c ./index.js 3:0-47
./c.js 39 bytes [built] ./c.js 39 bytes [built]
chunk default/782.js (id hint: vendors) 204 bytes <{179}> ={31}= [rendered] split chunk (cache group: defaultVendors)
> ./d ./index.js 4:0-47
./node_modules/shared.js?3 102 bytes [built]
./node_modules/shared.js?4 102 bytes [built]
chunk default/async-a.js (async-a) 141 bytes <{179}> [rendered] chunk default/async-a.js (async-a) 141 bytes <{179}> [rendered]
> ./a ./index.js 1:0-47 > ./a ./index.js 1:0-47
./a.js 39 bytes [built] ./a.js 39 bytes [built]

View File

@ -0,0 +1,3 @@
import "shared?3";
import "shared?4";
export default "d";

View File

@ -1,3 +1,4 @@
import(/* webpackChunkName: "async-a" */ "./a"); import(/* webpackChunkName: "async-a" */ "./a");
import(/* webpackChunkName: "async-b" */ "./b"); import(/* webpackChunkName: "async-b" */ "./b");
import(/* webpackChunkName: "async-c" */ "./c"); import(/* webpackChunkName: "async-c" */ "./c");
import(/* webpackChunkName: "async-d" */ "./d");

View File

@ -21,7 +21,8 @@ module.exports = {
}, },
optimization: { optimization: {
splitChunks: { splitChunks: {
minSize: 100 minSize: 100,
enforceSizeThreshold: 200
} }
}, },
stats stats

12
types.d.ts vendored
View File

@ -430,6 +430,7 @@ declare interface CacheGroupSource {
enforce?: boolean; enforce?: boolean;
minSize: Record<string, number>; minSize: Record<string, number>;
minRemainingSize: Record<string, number>; minRemainingSize: Record<string, number>;
enforceSizeThreshold: Record<string, number>;
maxAsyncSize: Record<string, number>; maxAsyncSize: Record<string, number>;
maxInitialSize: Record<string, number>; maxInitialSize: Record<string, number>;
minChunks?: number; minChunks?: number;
@ -4789,6 +4790,11 @@ declare interface OptimizationSplitChunksCacheGroup {
*/ */
enforce?: boolean; enforce?: boolean;
/**
* Size threshold at which splitting is enforced and other restrictions (minRemainingSize, maxAsyncRequests, maxInitialRequests) are ignored.
*/
enforceSizeThreshold?: OptimizationSplitChunksSizes;
/** /**
* Sets the template for the filename for created chunks. * Sets the template for the filename for created chunks.
*/ */
@ -4891,6 +4897,11 @@ declare interface OptimizationSplitChunksOptions {
*/ */
chunks?: "initial" | "async" | "all" | ((chunk: Chunk) => boolean); chunks?: "initial" | "async" | "all" | ((chunk: Chunk) => boolean);
/**
* Size threshold at which splitting is enforced and other restrictions (minRemainingSize, maxAsyncRequests, maxInitialRequests) are ignored.
*/
enforceSizeThreshold?: OptimizationSplitChunksSizes;
/** /**
* Options for modules not selected by any other cache group. * Options for modules not selected by any other cache group.
*/ */
@ -7368,6 +7379,7 @@ declare interface SplitChunksOptions {
chunksFilter: (chunk: Chunk) => boolean; chunksFilter: (chunk: Chunk) => boolean;
minSize: Record<string, number>; minSize: Record<string, number>;
minRemainingSize: Record<string, number>; minRemainingSize: Record<string, number>;
enforceSizeThreshold: Record<string, number>;
maxInitialSize: Record<string, number>; maxInitialSize: Record<string, number>;
maxAsyncSize: Record<string, number>; maxAsyncSize: Record<string, number>;
minChunks: number; minChunks: number;