| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";const Queue = require("../util/Queue");const { intersect } = require("../util/SetHelpers");const getParentChunksWithModule = (currentChunk, module) => {	const chunks = [];	const stack = new Set(currentChunk.parentsIterable);	for (const chunk of stack) {		if (chunk.containsModule(module)) {			chunks.push(chunk);		} else {			for (const parent of chunk.parentsIterable) {				stack.add(parent);			}		}	}	return chunks;};class RemoveParentModulesPlugin {	apply(compiler) {		compiler.hooks.compilation.tap("RemoveParentModulesPlugin", compilation => {			const handler = (chunks, chunkGroups) => {				const queue = new Queue();				const availableModulesMap = new WeakMap();				for (const chunkGroup of compilation.entrypoints.values()) {					// initialize available modules for chunks without parents					availableModulesMap.set(chunkGroup, new Set());					for (const child of chunkGroup.childrenIterable) {						queue.enqueue(child);					}				}				while (queue.length > 0) {					const chunkGroup = queue.dequeue();					let availableModules = availableModulesMap.get(chunkGroup);					let changed = false;					for (const parent of chunkGroup.parentsIterable) {						const availableModulesInParent = availableModulesMap.get(parent);						if (availableModulesInParent !== undefined) {							// If we know the available modules in parent: process these							if (availableModules === undefined) {								// if we have not own info yet: create new entry								availableModules = new Set(availableModulesInParent);								for (const chunk of parent.chunks) {									for (const m of chunk.modulesIterable) {										availableModules.add(m);									}								}								availableModulesMap.set(chunkGroup, availableModules);								changed = true;							} else {								for (const m of availableModules) {									if (										!parent.containsModule(m) &&										!availableModulesInParent.has(m)									) {										availableModules.delete(m);										changed = true;									}								}							}						}					}					if (changed) {						// if something changed: enqueue our children						for (const child of chunkGroup.childrenIterable) {							queue.enqueue(child);						}					}				}				// now we have available modules for every chunk				for (const chunk of chunks) {					const availableModulesSets = Array.from(						chunk.groupsIterable,						chunkGroup => availableModulesMap.get(chunkGroup)					);					if (availableModulesSets.some(s => s === undefined)) continue; // No info about this chunk group					const availableModules =						availableModulesSets.length === 1							? availableModulesSets[0]							: intersect(availableModulesSets);					const numberOfModules = chunk.getNumberOfModules();					const toRemove = new Set();					if (numberOfModules < availableModules.size) {						for (const m of chunk.modulesIterable) {							if (availableModules.has(m)) {								toRemove.add(m);							}						}					} else {						for (const m of availableModules) {							if (chunk.containsModule(m)) {								toRemove.add(m);							}						}					}					for (const module of toRemove) {						module.rewriteChunkInReasons(							chunk,							getParentChunksWithModule(chunk, module)						);						chunk.removeModule(module);					}				}			};			compilation.hooks.optimizeChunksBasic.tap(				"RemoveParentModulesPlugin",				handler			);			compilation.hooks.optimizeExtractedChunksBasic.tap(				"RemoveParentModulesPlugin",				handler			);		});	}}module.exports = RemoveParentModulesPlugin;
 |