| 
									
										
										
										
											2013-01-31 01:49:25 +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 02:44:01 +08:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-31 04:30:27 +08:00
										 |  |  | const { STAGE_BASIC } = require("../OptimizationStages"); | 
					
						
							| 
									
										
										
										
											2017-11-25 00:23:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-04 01:52:25 +08:00
										 |  |  | /** @typedef {import("../Chunk")} Chunk */ | 
					
						
							|  |  |  | /** @typedef {import("../ChunkGroup")} ChunkGroup */ | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | /** @typedef {import("../Compiler")} Compiler */ | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | /** @typedef {import("../Module")} Module */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Intersects multiple masks represented as bigints | 
					
						
							|  |  |  |  * @param {bigint[]} masks The module masks to intersect | 
					
						
							|  |  |  |  * @returns {bigint} The intersection of all masks | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function intersectMasks(masks) { | 
					
						
							|  |  |  | 	let result = masks[0]; | 
					
						
							|  |  |  | 	for (let i = masks.length - 1; i >= 1; i--) { | 
					
						
							|  |  |  | 		result &= masks[i]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ZERO_BIGINT = BigInt(0); | 
					
						
							|  |  |  | const ONE_BIGINT = BigInt(1); | 
					
						
							|  |  |  | const THIRTY_TWO_BIGINT = BigInt(32); | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 09:12:47 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Parses the module mask and returns the modules represented by it | 
					
						
							|  |  |  |  * @param {bigint} mask the module mask | 
					
						
							|  |  |  |  * @param {Module[]} ordinalModules the modules in the order they were added to the mask (LSB is index 0) | 
					
						
							|  |  |  |  * @returns {Generator<Module>} the modules represented by the mask | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function* getModulesFromMask(mask, ordinalModules) { | 
					
						
							|  |  |  | 	let offset = 31; | 
					
						
							|  |  |  | 	while (mask !== ZERO_BIGINT) { | 
					
						
							|  |  |  | 		// Consider the last 32 bits, since that's what Math.clz32 can handle
 | 
					
						
							|  |  |  | 		let last32 = Number(BigInt.asUintN(32, mask)); | 
					
						
							|  |  |  | 		while (last32 > 0) { | 
					
						
							|  |  |  | 			let last = Math.clz32(last32); | 
					
						
							|  |  |  | 			// The number of trailing zeros is the number trimmed off the input mask + 31 - the number of leading zeros
 | 
					
						
							|  |  |  | 			// The 32 is baked into the initial value of offset
 | 
					
						
							|  |  |  | 			const moduleIndex = offset - last; | 
					
						
							|  |  |  | 			// The number of trailing zeros is the index into the array generated by getOrCreateModuleMask
 | 
					
						
							|  |  |  | 			const module = ordinalModules[moduleIndex]; | 
					
						
							|  |  |  | 			yield module; | 
					
						
							|  |  |  | 			// Remove the matched module from the mask
 | 
					
						
							|  |  |  | 			// Since we can only count leading zeros, not trailing, we can't just downshift the mask
 | 
					
						
							|  |  |  | 			last32 &= ~(1 << (31 - last)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Remove the processed chunk from the mask
 | 
					
						
							|  |  |  | 		mask >>= THIRTY_TWO_BIGINT; | 
					
						
							|  |  |  | 		offset += 32; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-05 02:44:01 +08:00
										 |  |  | class RemoveParentModulesPlugin { | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Compiler} compiler the compiler | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-01-05 02:44:01 +08:00
										 |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		compiler.hooks.compilation.tap("RemoveParentModulesPlugin", compilation => { | 
					
						
							| 
									
										
										
										
											2023-06-04 01:52:25 +08:00
										 |  |  | 			/** | 
					
						
							|  |  |  | 			 * @param {Iterable<Chunk>} chunks the chunks | 
					
						
							|  |  |  | 			 * @param {ChunkGroup[]} chunkGroups the chunk groups | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			const handler = (chunks, chunkGroups) => { | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 				const chunkGraph = compilation.chunkGraph; | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 				const queue = new Set(); | 
					
						
							| 
									
										
										
										
											2018-04-27 20:23:48 +08:00
										 |  |  | 				const availableModulesMap = new WeakMap(); | 
					
						
							| 
									
										
										
										
											2017-01-24 02:52:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 				let nextModuleMask = ONE_BIGINT; | 
					
						
							|  |  |  | 				const maskByModule = new WeakMap(); | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | 				/** @type {Module[]} */ | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 				const ordinalModules = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				/** | 
					
						
							|  |  |  | 				 * Gets or creates a unique mask for a module | 
					
						
							|  |  |  | 				 * @param {Module} mod the module to get the mask for | 
					
						
							|  |  |  | 				 * @returns {bigint} the module mask to uniquely identify the module | 
					
						
							|  |  |  | 				 */ | 
					
						
							|  |  |  | 				const getOrCreateModuleMask = mod => { | 
					
						
							|  |  |  | 					let id = maskByModule.get(mod); | 
					
						
							|  |  |  | 					if (id === undefined) { | 
					
						
							|  |  |  | 						id = nextModuleMask; | 
					
						
							|  |  |  | 						ordinalModules.push(mod); | 
					
						
							|  |  |  | 						maskByModule.set(mod, id); | 
					
						
							|  |  |  | 						nextModuleMask <<= ONE_BIGINT; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					return id; | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Initialize masks by chunk and by chunk group for quicker comparisons
 | 
					
						
							|  |  |  | 				const chunkMasks = new WeakMap(); | 
					
						
							|  |  |  | 				for (const chunk of chunks) { | 
					
						
							|  |  |  | 					let mask = ZERO_BIGINT; | 
					
						
							|  |  |  | 					for (const m of chunkGraph.getChunkModulesIterable(chunk)) { | 
					
						
							|  |  |  | 						const id = getOrCreateModuleMask(m); | 
					
						
							|  |  |  | 						mask |= id; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2024-01-23 09:12:47 +08:00
										 |  |  | 					chunkMasks.set(chunk, mask); | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				const chunkGroupMasks = new WeakMap(); | 
					
						
							|  |  |  | 				for (const chunkGroup of chunkGroups) { | 
					
						
							|  |  |  | 					let mask = ZERO_BIGINT; | 
					
						
							|  |  |  | 					for (const chunk of chunkGroup.chunks) { | 
					
						
							| 
									
										
										
										
											2024-01-23 09:12:47 +08:00
										 |  |  | 						const chunkMask = chunkMasks.get(chunk); | 
					
						
							|  |  |  | 						if (chunkMask !== undefined) { | 
					
						
							|  |  |  | 							mask |= chunkMask; | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2024-01-23 09:12:47 +08:00
										 |  |  | 					chunkGroupMasks.set(chunkGroup, mask); | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				for (const chunkGroup of compilation.entrypoints.values()) { | 
					
						
							| 
									
										
										
										
											2017-11-25 00:23:33 +08:00
										 |  |  | 					// initialize available modules for chunks without parents
 | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 					availableModulesMap.set(chunkGroup, ZERO_BIGINT); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					for (const child of chunkGroup.childrenIterable) { | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 						queue.add(child); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-11-25 00:23:33 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-09-08 00:02:14 +08:00
										 |  |  | 				for (const chunkGroup of compilation.asyncEntrypoints) { | 
					
						
							|  |  |  | 					// initialize available modules for chunks without parents
 | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 					availableModulesMap.set(chunkGroup, ZERO_BIGINT); | 
					
						
							| 
									
										
										
										
											2020-09-08 00:02:14 +08:00
										 |  |  | 					for (const child of chunkGroup.childrenIterable) { | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 						queue.add(child); | 
					
						
							| 
									
										
										
										
											2020-09-08 00:02:14 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-01-24 02:52:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 				for (const chunkGroup of queue) { | 
					
						
							|  |  |  | 					let availableModulesMask = availableModulesMap.get(chunkGroup); | 
					
						
							| 
									
										
										
										
											2017-11-25 00:23:33 +08:00
										 |  |  | 					let changed = false; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					for (const parent of chunkGroup.parentsIterable) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 						const availableModulesInParent = availableModulesMap.get(parent); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						if (availableModulesInParent !== undefined) { | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 							const parentMask = | 
					
						
							| 
									
										
										
										
											2024-01-23 09:12:47 +08:00
										 |  |  | 								availableModulesInParent | chunkGroupMasks.get(parent); | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 							// If we know the available modules in parent: process these
 | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 							if (availableModulesMask === undefined) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 								// if we have not own info yet: create new entry
 | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 								availableModulesMask = parentMask; | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 								changed = true; | 
					
						
							|  |  |  | 							} else { | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 								let newMask = availableModulesMask & parentMask; | 
					
						
							|  |  |  | 								if (newMask !== availableModulesMask) { | 
					
						
							|  |  |  | 									changed = true; | 
					
						
							|  |  |  | 									availableModulesMask = newMask; | 
					
						
							| 
									
										
										
										
											2017-11-25 00:23:33 +08:00
										 |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2017-01-05 02:44:01 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-01-24 02:52:47 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (changed) { | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 						availableModulesMap.set(chunkGroup, availableModulesMask); | 
					
						
							| 
									
										
										
										
											2017-11-25 00:23:33 +08:00
										 |  |  | 						// if something changed: enqueue our children
 | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 						for (const child of chunkGroup.childrenIterable) { | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 							// Push the child to the end of the queue
 | 
					
						
							|  |  |  | 							queue.delete(child); | 
					
						
							|  |  |  | 							queue.add(child); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-11-25 00:23:33 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// now we have available modules for every chunk
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				for (const chunk of chunks) { | 
					
						
							| 
									
										
										
										
											2024-01-23 09:12:47 +08:00
										 |  |  | 					const chunkMask = chunkMasks.get(chunk); | 
					
						
							|  |  |  | 					if (chunkMask === undefined) continue; // No info about this chunk
 | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					const availableModulesSets = Array.from( | 
					
						
							|  |  |  | 						chunk.groupsIterable, | 
					
						
							|  |  |  | 						chunkGroup => availableModulesMap.get(chunkGroup) | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					if (availableModulesSets.some(s => s === undefined)) continue; // No info about this chunk group
 | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					const availableModulesMask = intersectMasks(availableModulesSets); | 
					
						
							| 
									
										
										
										
											2024-01-23 09:12:47 +08:00
										 |  |  | 					const toRemoveMask = chunkMask & availableModulesMask; | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 					if (toRemoveMask !== ZERO_BIGINT) { | 
					
						
							| 
									
										
										
										
											2024-01-23 09:12:47 +08:00
										 |  |  | 						for (const module of getModulesFromMask( | 
					
						
							|  |  |  | 							toRemoveMask, | 
					
						
							|  |  |  | 							ordinalModules | 
					
						
							|  |  |  | 						)) { | 
					
						
							| 
									
										
										
										
											2024-01-23 09:03:07 +08:00
										 |  |  | 							chunkGraph.disconnectChunkAndModule(chunk, module); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-11-25 00:23:33 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-01-24 02:52:47 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-12-14 04:35:39 +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: "RemoveParentModulesPlugin", | 
					
						
							|  |  |  | 					stage: STAGE_BASIC | 
					
						
							| 
									
										
										
										
											2018-12-09 19:54:17 +08:00
										 |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				handler | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-01-05 02:44:01 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports = RemoveParentModulesPlugin; |