improve way of getting combinations of chunks

we no longer require a complexity limit -> maxComplexity removed
This commit is contained in:
Tobias Koppers 2018-02-17 09:48:40 +01:00
parent cc0d29a90e
commit 244d27a42d
5 changed files with 36 additions and 33 deletions

View File

@ -168,7 +168,6 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
this.set("optimization.usedExports", "make", options => isProductionLikeMode(options));
this.set("optimization.concatenateModules", "make", options => isProductionLikeMode(options));
this.set("optimization.splitChunks", {});
this.set("optimization.splitChunks.maxComplexity", "make", options => isProductionLikeMode(options) ? 3 : 1);
this.set("optimization.splitChunks.chunks", "async");
this.set("optimization.splitChunks.minSize", 30000);
this.set("optimization.splitChunks.minChunks", 1);

View File

@ -7,6 +7,7 @@
const crypto = require("crypto");
const SortableSet = require("../util/SortableSet");
const GraphHelpers = require("../GraphHelpers");
const isSubset = require("../util/SetHelpers").isSubset;
const hashFilename = (name) => {
return crypto.createHash("md5").update(name).digest("hex").slice(0, 8);
@ -40,23 +41,6 @@ const isOverlap = (a, b) => {
return false;
};
const getCombinations = (array, maxDepth) => {
const results = [];
getCombinationsInteral(array, maxDepth, results);
return results;
};
const getCombinationsInteral = (array, maxDepth, results) => {
results.push(array);
if(maxDepth === 0 || array.length === 1) {
return;
}
for(let i = 0; i < array.length; i++) {
const newArray = array.slice(0, i).concat(array.slice(i + 1, array.length));
getCombinationsInteral(newArray, maxDepth - 1, results);
}
};
const compareEntries = (a, b) => {
// 1. by priority
const diffPriority = a.cacheGroup.priority - b.cacheGroup.priority;
@ -97,7 +81,6 @@ module.exports = class SplitChunksPlugin {
static normalizeOptions(options) {
return {
maxComplexity: options.maxComplexity || 0,
chunks: options.chunks || "all",
minSize: options.minSize || 0,
minChunks: options.minChunks || 1,
@ -227,6 +210,25 @@ module.exports = class SplitChunksPlugin {
for(const chunk of chunks) {
indexMap.set(chunk, index++);
}
const getKey = chunks => {
return Array.from(chunks, c => indexMap.get(c)).sort().join();
};
// Create a list of possible combinations
const chunkSetsInGraph = new Map(); // Map<string, Set<Chunk>>
for(const module of compilation.modules) {
const chunkIndices = getKey(module.chunksIterable);
chunkSetsInGraph.set(chunkIndices, new Set(module.chunksIterable));
}
const combinations = new Map(); // Map<string, Set<Chunk>[]>
for(const [key, chunksSet] of chunkSetsInGraph) {
var array = [];
for(const set of chunkSetsInGraph.values()) {
if(isSubset(chunksSet, set)) {
array.push(set);
}
}
combinations.set(key, array);
}
// Map a list of chunks to a list of modules
// For the key the chunk "index" is used, the value is a SortableSet of modules
const chunksInfoMap = new Map();
@ -249,24 +251,24 @@ module.exports = class SplitChunksPlugin {
getName: cacheGroupSource.getName !== undefined ? cacheGroupSource.getName : this.options.getName,
reuseExistingChunk: cacheGroupSource.reuseExistingChunk
};
// Select chunks by configuration
const maxSelectedChunks = cacheGroup.chunks === "initial" ? chunks.filter(chunk => chunk.canBeInitial()) :
cacheGroup.chunks === "async" ? chunks.filter(chunk => !chunk.canBeInitial()) :
chunks;
// For all (nearly all) combination of chunk selection
for(const selectedChunks of getCombinations(maxSelectedChunks, this.options.maxComplexity)) {
// For all combination of chunk selection
for(const chunkCombination of combinations.get(getKey(chunks))) {
// Get indices of chunks in which this module occurs
const chunkIndices = selectedChunks.map(chunk => indexMap.get(chunk));
const chunkIndices = Array.from(chunkCombination, chunk => indexMap.get(chunk));
// Break if minimum number of chunks is not reached
if(chunkIndices.length < cacheGroup.minChunks)
continue;
// Select chunks by configuration
const selectedChunks = cacheGroup.chunks === "initial" ? Array.from(chunkCombination).filter(chunk => chunk.canBeInitial()) :
cacheGroup.chunks === "async" ? Array.from(chunkCombination).filter(chunk => !chunk.canBeInitial()) :
Array.from(chunkCombination);
// Determine name for split chunk
const name = cacheGroup.getName(module, selectedChunks, cacheGroup.key);
// Create key for maps
// When it has a name we use the name as key
// Elsewise we create the key from chunks and cache group key
// This automatically merges equal names
const chunksKey = chunkIndices.sort().join();
const chunksKey = getKey(selectedChunks);
const key = name && `name:${name}` ||
`chunks:${chunksKey} key:${cacheGroup.key}`;
// Add module to maps

View File

@ -24,3 +24,11 @@ exports.intersect = sets => {
}
return current;
};
exports.isSubset = (bigSet, smallSet) => {
if(bigSet.size < smallSet.size) return false;
for(const item of smallSet) {
if(!bigSet.has(item)) return false;
}
return true;
};

View File

@ -1335,11 +1335,6 @@
"type": "object",
"additionalProperties": false,
"properties": {
"maxComplexity": {
"description": "Limits the algorithmic complexity",
"type": "number",
"minimum": 0
},
"chunks": {
"description": "Select chunks for determining shared modules (defaults to \"async\", \"initial\" and \"all\" requires adding these chunks to the HTML)",
"enum": [

View File

@ -18,7 +18,6 @@ module.exports = {
},
optimization: {
splitChunks: {
maxComplexity: 100,
minSize: 100
}
},