| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";const { STAGE_BASIC } = require("../OptimizationStages");const createSchemaValidation = require("../util/create-schema-validation");const { runtimeEqual } = require("../util/runtime");/** @typedef {import("../../declarations/plugins/optimize/MergeDuplicateChunksPlugin").MergeDuplicateChunksPluginOptions} MergeDuplicateChunksPluginOptions *//** @typedef {import("../Compiler")} Compiler */const validate = createSchemaValidation(	require("../../schemas/plugins/optimize/MergeDuplicateChunksPlugin.check"),	() =>		require("../../schemas/plugins/optimize/MergeDuplicateChunksPlugin.json"),	{		name: "Merge Duplicate Chunks Plugin",		baseDataPath: "options"	});const PLUGIN_NAME = "MergeDuplicateChunksPlugin";class MergeDuplicateChunksPlugin {	/**	 * @param {MergeDuplicateChunksPluginOptions} options options object	 */	constructor(options = { stage: STAGE_BASIC }) {		validate(options);		this.options = options;	}	/**	 * @param {Compiler} compiler the compiler	 * @returns {void}	 */	apply(compiler) {		compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {			compilation.hooks.optimizeChunks.tap(				{					name: PLUGIN_NAME,					stage: this.options.stage				},				chunks => {					const { chunkGraph, moduleGraph } = compilation;					// remember already tested chunks for performance					const notDuplicates = new Set();					// for each chunk					for (const chunk of chunks) {						// track a Set of all chunk that could be duplicates						let possibleDuplicates;						for (const module of chunkGraph.getChunkModulesIterable(chunk)) {							if (possibleDuplicates === undefined) {								// when possibleDuplicates is not yet set,								// create a new Set from chunks of the current module								// including only chunks with the same number of modules								for (const dup of chunkGraph.getModuleChunksIterable(module)) {									if (										dup !== chunk &&										chunkGraph.getNumberOfChunkModules(chunk) ===											chunkGraph.getNumberOfChunkModules(dup) &&										!notDuplicates.has(dup)									) {										// delay allocating the new Set until here, reduce memory pressure										if (possibleDuplicates === undefined) {											possibleDuplicates = new Set();										}										possibleDuplicates.add(dup);									}								}								// when no chunk is possible we can break here								if (possibleDuplicates === undefined) break;							} else {								// validate existing possible duplicates								for (const dup of possibleDuplicates) {									// remove possible duplicate when module is not contained									if (!chunkGraph.isModuleInChunk(module, dup)) {										possibleDuplicates.delete(dup);									}								}								// when all chunks has been removed we can break here								if (possibleDuplicates.size === 0) break;							}						}						// when we found duplicates						if (							possibleDuplicates !== undefined &&							possibleDuplicates.size > 0						) {							outer: for (const otherChunk of possibleDuplicates) {								if (otherChunk.hasRuntime() !== chunk.hasRuntime()) continue;								if (chunkGraph.getNumberOfEntryModules(chunk) > 0) continue;								if (chunkGraph.getNumberOfEntryModules(otherChunk) > 0) {									continue;								}								if (!runtimeEqual(chunk.runtime, otherChunk.runtime)) {									for (const module of chunkGraph.getChunkModulesIterable(										chunk									)) {										const exportsInfo = moduleGraph.getExportsInfo(module);										if (											!exportsInfo.isEquallyUsed(												chunk.runtime,												otherChunk.runtime											)										) {											continue outer;										}									}								}								// merge them								if (chunkGraph.canChunksBeIntegrated(chunk, otherChunk)) {									chunkGraph.integrateChunks(chunk, otherChunk);									compilation.chunks.delete(otherChunk);								}							}						}						// don't check already processed chunks twice						notDuplicates.add(chunk);					}				}			);		});	}}module.exports = MergeDuplicateChunksPlugin;
 |