diff --git a/lib/WebpackOptionsDefaulter.js b/lib/WebpackOptionsDefaulter.js index 487fe2f3c..a3b5ee65a 100644 --- a/lib/WebpackOptionsDefaulter.js +++ b/lib/WebpackOptionsDefaulter.js @@ -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); diff --git a/lib/optimize/SplitChunksPlugin.js b/lib/optimize/SplitChunksPlugin.js index d5b59b842..90264ca13 100644 --- a/lib/optimize/SplitChunksPlugin.js +++ b/lib/optimize/SplitChunksPlugin.js @@ -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> + for(const module of compilation.modules) { + const chunkIndices = getKey(module.chunksIterable); + chunkSetsInGraph.set(chunkIndices, new Set(module.chunksIterable)); + } + const combinations = new Map(); // Map[]> + 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 diff --git a/lib/util/SetHelpers.js b/lib/util/SetHelpers.js index 2a6da2b67..d134a6fd2 100644 --- a/lib/util/SetHelpers.js +++ b/lib/util/SetHelpers.js @@ -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; +}; diff --git a/schemas/WebpackOptions.json b/schemas/WebpackOptions.json index 57383a94e..93969552e 100644 --- a/schemas/WebpackOptions.json +++ b/schemas/WebpackOptions.json @@ -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": [ diff --git a/test/statsCases/split-chunks-combinations/webpack.config.js b/test/statsCases/split-chunks-combinations/webpack.config.js index a046c50ff..536c5f125 100644 --- a/test/statsCases/split-chunks-combinations/webpack.config.js +++ b/test/statsCases/split-chunks-combinations/webpack.config.js @@ -18,7 +18,6 @@ module.exports = { }, optimization: { splitChunks: { - maxComplexity: 100, minSize: 100 } },