diff options
author | 2020-11-16 00:10:28 +0100 | |
---|---|---|
committer | 2020-11-16 00:10:28 +0100 | |
commit | e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d (patch) | |
tree | 55713f725f77b44ebfec86e4eec3ce33e71458ca /node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js | |
download | website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.tar.gz website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.tar.bz2 website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.zip |
api, login, auth
Diffstat (limited to 'node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js')
-rw-r--r-- | node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js b/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js new file mode 100644 index 0000000..3843878 --- /dev/null +++ b/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js @@ -0,0 +1,294 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const identifierUtils = require("../util/identifier"); +const { intersect } = require("../util/SetHelpers"); +const validateOptions = require("schema-utils"); +const schema = require("../../schemas/plugins/optimize/AggressiveSplittingPlugin.json"); + +/** @typedef {import("../../declarations/plugins/optimize/AggressiveSplittingPlugin").AggressiveSplittingPluginOptions} AggressiveSplittingPluginOptions */ + +const moveModuleBetween = (oldChunk, newChunk) => { + return module => { + oldChunk.moveModule(module, newChunk); + }; +}; + +const isNotAEntryModule = entryModule => { + return module => { + return entryModule !== module; + }; +}; + +class AggressiveSplittingPlugin { + /** + * @param {AggressiveSplittingPluginOptions=} options options object + */ + constructor(options) { + if (!options) options = {}; + + validateOptions(schema, options, "Aggressive Splitting Plugin"); + + this.options = options; + if (typeof this.options.minSize !== "number") { + this.options.minSize = 30 * 1024; + } + if (typeof this.options.maxSize !== "number") { + this.options.maxSize = 50 * 1024; + } + if (typeof this.options.chunkOverhead !== "number") { + this.options.chunkOverhead = 0; + } + if (typeof this.options.entryChunkMultiplicator !== "number") { + this.options.entryChunkMultiplicator = 1; + } + } + apply(compiler) { + compiler.hooks.thisCompilation.tap( + "AggressiveSplittingPlugin", + compilation => { + let needAdditionalSeal = false; + let newSplits; + let fromAggressiveSplittingSet; + let chunkSplitDataMap; + compilation.hooks.optimize.tap("AggressiveSplittingPlugin", () => { + newSplits = []; + fromAggressiveSplittingSet = new Set(); + chunkSplitDataMap = new Map(); + }); + compilation.hooks.optimizeChunksAdvanced.tap( + "AggressiveSplittingPlugin", + chunks => { + // Precompute stuff + const nameToModuleMap = new Map(); + const moduleToNameMap = new Map(); + for (const m of compilation.modules) { + const name = identifierUtils.makePathsRelative( + compiler.context, + m.identifier(), + compilation.cache + ); + nameToModuleMap.set(name, m); + moduleToNameMap.set(m, name); + } + + // Check used chunk ids + const usedIds = new Set(); + for (const chunk of chunks) { + usedIds.add(chunk.id); + } + + const recordedSplits = + (compilation.records && compilation.records.aggressiveSplits) || + []; + const usedSplits = newSplits + ? recordedSplits.concat(newSplits) + : recordedSplits; + + const minSize = this.options.minSize; + const maxSize = this.options.maxSize; + + const applySplit = splitData => { + // Cannot split if id is already taken + if (splitData.id !== undefined && usedIds.has(splitData.id)) { + return false; + } + + // Get module objects from names + const selectedModules = splitData.modules.map(name => + nameToModuleMap.get(name) + ); + + // Does the modules exist at all? + if (!selectedModules.every(Boolean)) return false; + + // Check if size matches (faster than waiting for hash) + const size = selectedModules.reduce( + (sum, m) => sum + m.size(), + 0 + ); + if (size !== splitData.size) return false; + + // get chunks with all modules + const selectedChunks = intersect( + selectedModules.map(m => new Set(m.chunksIterable)) + ); + + // No relevant chunks found + if (selectedChunks.size === 0) return false; + + // The found chunk is already the split or similar + if ( + selectedChunks.size === 1 && + Array.from(selectedChunks)[0].getNumberOfModules() === + selectedModules.length + ) { + const chunk = Array.from(selectedChunks)[0]; + if (fromAggressiveSplittingSet.has(chunk)) return false; + fromAggressiveSplittingSet.add(chunk); + chunkSplitDataMap.set(chunk, splitData); + return true; + } + + // split the chunk into two parts + const newChunk = compilation.addChunk(); + newChunk.chunkReason = "aggressive splitted"; + for (const chunk of selectedChunks) { + selectedModules.forEach(moveModuleBetween(chunk, newChunk)); + chunk.split(newChunk); + chunk.name = null; + } + fromAggressiveSplittingSet.add(newChunk); + chunkSplitDataMap.set(newChunk, splitData); + + if (splitData.id !== null && splitData.id !== undefined) { + newChunk.id = splitData.id; + } + return true; + }; + + // try to restore to recorded splitting + let changed = false; + for (let j = 0; j < usedSplits.length; j++) { + const splitData = usedSplits[j]; + if (applySplit(splitData)) changed = true; + } + + // for any chunk which isn't splitted yet, split it and create a new entry + // start with the biggest chunk + const sortedChunks = chunks.slice().sort((a, b) => { + const diff1 = b.modulesSize() - a.modulesSize(); + if (diff1) return diff1; + const diff2 = a.getNumberOfModules() - b.getNumberOfModules(); + if (diff2) return diff2; + const modulesA = Array.from(a.modulesIterable); + const modulesB = Array.from(b.modulesIterable); + modulesA.sort(); + modulesB.sort(); + const aI = modulesA[Symbol.iterator](); + const bI = modulesB[Symbol.iterator](); + // eslint-disable-next-line no-constant-condition + while (true) { + const aItem = aI.next(); + const bItem = bI.next(); + if (aItem.done) return 0; + const aModuleIdentifier = aItem.value.identifier(); + const bModuleIdentifier = bItem.value.identifier(); + if (aModuleIdentifier > bModuleIdentifier) return -1; + if (aModuleIdentifier < bModuleIdentifier) return 1; + } + }); + for (const chunk of sortedChunks) { + if (fromAggressiveSplittingSet.has(chunk)) continue; + const size = chunk.modulesSize(); + if (size > maxSize && chunk.getNumberOfModules() > 1) { + const modules = chunk + .getModules() + .filter(isNotAEntryModule(chunk.entryModule)) + .sort((a, b) => { + a = a.identifier(); + b = b.identifier(); + if (a > b) return 1; + if (a < b) return -1; + return 0; + }); + const selectedModules = []; + let selectedModulesSize = 0; + for (let k = 0; k < modules.length; k++) { + const module = modules[k]; + const newSize = selectedModulesSize + module.size(); + if (newSize > maxSize && selectedModulesSize >= minSize) { + break; + } + selectedModulesSize = newSize; + selectedModules.push(module); + } + if (selectedModules.length === 0) continue; + const splitData = { + modules: selectedModules + .map(m => moduleToNameMap.get(m)) + .sort(), + size: selectedModulesSize + }; + + if (applySplit(splitData)) { + newSplits = (newSplits || []).concat(splitData); + changed = true; + } + } + } + if (changed) return true; + } + ); + compilation.hooks.recordHash.tap( + "AggressiveSplittingPlugin", + records => { + // 4. save made splittings to records + const allSplits = new Set(); + const invalidSplits = new Set(); + + // Check if some splittings are invalid + // We remove invalid splittings and try again + for (const chunk of compilation.chunks) { + const splitData = chunkSplitDataMap.get(chunk); + if (splitData !== undefined) { + if (splitData.hash && chunk.hash !== splitData.hash) { + // Split was successful, but hash doesn't equal + // We can throw away the split since it's useless now + invalidSplits.add(splitData); + } + } + } + + if (invalidSplits.size > 0) { + records.aggressiveSplits = records.aggressiveSplits.filter( + splitData => !invalidSplits.has(splitData) + ); + needAdditionalSeal = true; + } else { + // set hash and id values on all (new) splittings + for (const chunk of compilation.chunks) { + const splitData = chunkSplitDataMap.get(chunk); + if (splitData !== undefined) { + splitData.hash = chunk.hash; + splitData.id = chunk.id; + allSplits.add(splitData); + // set flag for stats + chunk.recorded = true; + } + } + + // Also add all unused historial splits (after the used ones) + // They can still be used in some future compilation + const recordedSplits = + compilation.records && compilation.records.aggressiveSplits; + if (recordedSplits) { + for (const splitData of recordedSplits) { + if (!invalidSplits.has(splitData)) allSplits.add(splitData); + } + } + + // record all splits + records.aggressiveSplits = Array.from(allSplits); + + needAdditionalSeal = false; + } + } + ); + compilation.hooks.needAdditionalSeal.tap( + "AggressiveSplittingPlugin", + () => { + if (needAdditionalSeal) { + needAdditionalSeal = false; + return true; + } + } + ); + } + ); + } +} +module.exports = AggressiveSplittingPlugin; |