| 
									
										
										
										
											2016-07-13 17:03:14 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-05 03:15:54 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2016-07-13 17:03:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 17:19:28 +08:00
										 |  |  | const validateOptions = require("schema-utils"); | 
					
						
							| 
									
										
										
										
											2017-11-11 20:05:55 +08:00
										 |  |  | const schema = require("../../schemas/plugins/optimize/AggressiveSplittingPlugin.json"); | 
					
						
							| 
									
										
										
										
											2018-07-31 04:30:27 +08:00
										 |  |  | const { STAGE_ADVANCED } = require("../OptimizationStages"); | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | const { intersect } = require("../util/SetHelpers"); | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | const { | 
					
						
							| 
									
										
										
										
											2018-08-28 21:07:28 +08:00
										 |  |  | 	compareModulesByIdentifier, | 
					
						
							| 
									
										
										
										
											2018-10-21 17:26:17 +08:00
										 |  |  | 	compareChunks | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | } = require("../util/comparators"); | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | const identifierUtils = require("../util/identifier"); | 
					
						
							| 
									
										
										
										
											2017-10-28 05:23:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-20 16:13:55 +08:00
										 |  |  | /** @typedef {import("../../declarations/plugins/optimize/AggressiveSplittingPlugin").AggressiveSplittingPluginOptions} AggressiveSplittingPluginOptions */ | 
					
						
							| 
									
										
										
										
											2018-07-20 19:35:01 +08:00
										 |  |  | /** @typedef {import("../Chunk")} Chunk */ | 
					
						
							| 
									
										
										
										
											2018-08-14 22:40:37 +08:00
										 |  |  | /** @typedef {import("../ChunkGraph")} ChunkGraph */ | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | /** @typedef {import("../Compiler")} Compiler */ | 
					
						
							| 
									
										
										
										
											2018-08-14 22:40:37 +08:00
										 |  |  | /** @typedef {import("../Module")} Module */ | 
					
						
							| 
									
										
										
										
											2018-07-20 19:35:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | const moveModuleBetween = (chunkGraph, oldChunk, newChunk) => { | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 	return module => { | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 		chunkGraph.disconnectChunkAndModule(oldChunk, module); | 
					
						
							|  |  |  | 		chunkGraph.connectChunkAndModule(newChunk, module); | 
					
						
							| 
									
										
										
										
											2017-01-11 17:51:58 +08:00
										 |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2016-10-29 17:11:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 22:40:37 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {ChunkGraph} chunkGraph the chunk graph | 
					
						
							|  |  |  |  * @param {Chunk} chunk the chunk | 
					
						
							|  |  |  |  * @returns {function(Module): boolean} filter for entry module | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const isNotAEntryModule = (chunkGraph, chunk) => { | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 	return module => { | 
					
						
							| 
									
										
										
										
											2018-08-14 22:40:37 +08:00
										 |  |  | 		return !chunkGraph.isEntryModuleInChunk(module, chunk); | 
					
						
							| 
									
										
										
										
											2017-01-11 17:51:58 +08:00
										 |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2016-07-13 17:03:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-20 19:35:01 +08:00
										 |  |  | /** @type {WeakSet<Chunk>} */ | 
					
						
							|  |  |  | const recordedChunks = new WeakSet(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-05 03:15:54 +08:00
										 |  |  | class AggressiveSplittingPlugin { | 
					
						
							| 
									
										
										
										
											2018-09-20 16:13:55 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {AggressiveSplittingPluginOptions=} options options object | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2018-09-25 22:07:42 +08:00
										 |  |  | 	constructor(options = {}) { | 
					
						
							| 
									
										
										
										
											2019-08-07 21:55:03 +08:00
										 |  |  | 		validateOptions(schema, options, { | 
					
						
							|  |  |  | 			name: "Aggressive Splitting Plugin", | 
					
						
							|  |  |  | 			baseDataPath: "options" | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-10-28 05:23:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-20 16:13:55 +08:00
										 |  |  | 		this.options = options; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (typeof this.options.minSize !== "number") { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			this.options.minSize = 30 * 1024; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (typeof this.options.maxSize !== "number") { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			this.options.maxSize = 50 * 1024; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (typeof this.options.chunkOverhead !== "number") { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			this.options.chunkOverhead = 0; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (typeof this.options.entryChunkMultiplicator !== "number") { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			this.options.entryChunkMultiplicator = 1; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-05 03:15:54 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-07-20 19:35:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Chunk} chunk the chunk to test | 
					
						
							|  |  |  | 	 * @returns {boolean} true if the chunk was recorded | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	static wasChunkRecorded(chunk) { | 
					
						
							|  |  |  | 		return recordedChunks.has(chunk); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2020-04-23 16:48:36 +08:00
										 |  |  | 	 * Apply the plugin | 
					
						
							|  |  |  | 	 * @param {Compiler} compiler the compiler instance | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-01-05 03:15:54 +08:00
										 |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		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(); | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2018-07-31 04:30:27 +08:00
										 |  |  | 				compilation.hooks.optimizeChunks.tap( | 
					
						
							| 
									
										
										
										
											2018-12-09 19:54:17 +08:00
										 |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2018-07-31 04:30:27 +08:00
										 |  |  | 						name: "AggressiveSplittingPlugin", | 
					
						
							|  |  |  | 						stage: STAGE_ADVANCED | 
					
						
							| 
									
										
										
										
											2018-12-09 19:54:17 +08:00
										 |  |  | 					}, | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					chunks => { | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 						const chunkGraph = compilation.chunkGraph; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						// Precompute stuff
 | 
					
						
							|  |  |  | 						const nameToModuleMap = new Map(); | 
					
						
							|  |  |  | 						const moduleToNameMap = new Map(); | 
					
						
							| 
									
										
										
										
											2020-04-17 16:54:27 +08:00
										 |  |  | 						const makePathsRelative = identifierUtils.makePathsRelative.bindContextCache( | 
					
						
							|  |  |  | 							compiler.context, | 
					
						
							|  |  |  | 							compiler.root | 
					
						
							|  |  |  | 						); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						for (const m of compilation.modules) { | 
					
						
							| 
									
										
										
										
											2020-04-17 16:54:27 +08:00
										 |  |  | 							const name = makePathsRelative(m.identifier()); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							nameToModuleMap.set(name, m); | 
					
						
							|  |  |  | 							moduleToNameMap.set(m, name); | 
					
						
							| 
									
										
										
										
											2017-01-05 03:15:54 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						// 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
 | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 							if (splitData.id !== undefined && usedIds.has(splitData.id)) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								return false; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							// 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)
 | 
					
						
							| 
									
										
										
										
											2020-01-20 21:41:39 +08:00
										 |  |  | 							let size = 0; | 
					
						
							|  |  |  | 							for (const m of selectedModules) size += m.size(); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							if (size !== splitData.size) return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// get chunks with all modules
 | 
					
						
							|  |  |  | 							const selectedChunks = intersect( | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 								selectedModules.map( | 
					
						
							|  |  |  | 									m => new Set(chunkGraph.getModuleChunksIterable(m)) | 
					
						
							|  |  |  | 								) | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// No relevant chunks found
 | 
					
						
							|  |  |  | 							if (selectedChunks.size === 0) return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// The found chunk is already the split or similar
 | 
					
						
							|  |  |  | 							if ( | 
					
						
							|  |  |  | 								selectedChunks.size === 1 && | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 								chunkGraph.getNumberOfChunkModules( | 
					
						
							|  |  |  | 									Array.from(selectedChunks)[0] | 
					
						
							|  |  |  | 								) === selectedModules.length | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							) { | 
					
						
							|  |  |  | 								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) { | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 								selectedModules.forEach( | 
					
						
							|  |  |  | 									moveModuleBetween(chunkGraph, chunk, newChunk) | 
					
						
							|  |  |  | 								); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								chunk.split(newChunk); | 
					
						
							|  |  |  | 								chunk.name = null; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							fromAggressiveSplittingSet.add(newChunk); | 
					
						
							|  |  |  | 							chunkSplitDataMap.set(newChunk, splitData); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							if (splitData.id !== null && splitData.id !== undefined) { | 
					
						
							|  |  |  | 								newChunk.id = splitData.id; | 
					
						
							| 
									
										
										
										
											2018-09-05 20:22:10 +08:00
										 |  |  | 								newChunk.ids = [splitData.id]; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							} | 
					
						
							|  |  |  | 							return true; | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 						}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						// 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; | 
					
						
							| 
									
										
										
										
											2016-07-13 17:03:14 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						// for any chunk which isn't splitted yet, split it and create a new entry
 | 
					
						
							|  |  |  | 						// start with the biggest chunk
 | 
					
						
							| 
									
										
										
										
											2018-10-21 17:26:17 +08:00
										 |  |  | 						const cmpFn = compareChunks(chunkGraph); | 
					
						
							| 
									
										
										
										
											2018-09-06 22:59:11 +08:00
										 |  |  | 						const sortedChunks = Array.from(chunks).sort((a, b) => { | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 							const diff1 = | 
					
						
							|  |  |  | 								chunkGraph.getChunkModulesSize(b) - | 
					
						
							|  |  |  | 								chunkGraph.getChunkModulesSize(a); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							if (diff1) return diff1; | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 							const diff2 = | 
					
						
							|  |  |  | 								chunkGraph.getNumberOfChunkModules(a) - | 
					
						
							|  |  |  | 								chunkGraph.getNumberOfChunkModules(b); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							if (diff2) return diff2; | 
					
						
							| 
									
										
										
										
											2018-10-21 17:26:17 +08:00
										 |  |  | 							return cmpFn(a, b); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						}); | 
					
						
							|  |  |  | 						for (const chunk of sortedChunks) { | 
					
						
							|  |  |  | 							if (fromAggressiveSplittingSet.has(chunk)) continue; | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 							const size = chunkGraph.getChunkModulesSize(chunk); | 
					
						
							|  |  |  | 							if ( | 
					
						
							|  |  |  | 								size > maxSize && | 
					
						
							|  |  |  | 								chunkGraph.getNumberOfChunkModules(chunk) > 1 | 
					
						
							|  |  |  | 							) { | 
					
						
							|  |  |  | 								const modules = chunkGraph | 
					
						
							| 
									
										
										
										
											2018-10-21 17:26:17 +08:00
										 |  |  | 									.getOrderedChunkModules(chunk, compareModulesByIdentifier) | 
					
						
							|  |  |  | 									.filter(isNotAEntryModule(chunkGraph, chunk)); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								const selectedModules = []; | 
					
						
							|  |  |  | 								let selectedModulesSize = 0; | 
					
						
							|  |  |  | 								for (let k = 0; k < modules.length; k++) { | 
					
						
							|  |  |  | 									const module = modules[k]; | 
					
						
							|  |  |  | 									const newSize = selectedModulesSize + module.size(); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 									if (newSize > maxSize && selectedModulesSize >= minSize) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 										break; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 									} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 									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; | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2016-07-13 17:03:14 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						if (changed) return true; | 
					
						
							| 
									
										
										
										
											2016-07-13 17:03:14 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				); | 
					
						
							|  |  |  | 				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); | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						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
 | 
					
						
							| 
									
										
										
										
											2018-07-20 19:35:01 +08:00
										 |  |  | 									recordedChunks.add(chunk); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:51:26 +08:00
										 |  |  | 							// Also add all unused historical splits (after the used ones)
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							// 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); | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							// record all splits
 | 
					
						
							|  |  |  | 							records.aggressiveSplits = Array.from(allSplits); | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							needAdditionalSeal = false; | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-01-22 20:52:43 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				); | 
					
						
							|  |  |  | 				compilation.hooks.needAdditionalSeal.tap( | 
					
						
							|  |  |  | 					"AggressiveSplittingPlugin", | 
					
						
							|  |  |  | 					() => { | 
					
						
							|  |  |  | 						if (needAdditionalSeal) { | 
					
						
							|  |  |  | 							needAdditionalSeal = false; | 
					
						
							|  |  |  | 							return true; | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2017-01-05 03:15:54 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports = AggressiveSplittingPlugin; |