| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";/** @typedef {import("../Chunk")} Chunk *//** @typedef {import("../Chunk").ChunkId} ChunkId *//** @typedef {import("../Compiler")} Compiler *//** @typedef {import("../Module")} Module */class FlagIncludedChunksPlugin {	/**	 * Apply the plugin	 * @param {Compiler} compiler the compiler instance	 * @returns {void}	 */	apply(compiler) {		compiler.hooks.compilation.tap("FlagIncludedChunksPlugin", compilation => {			compilation.hooks.optimizeChunkIds.tap(				"FlagIncludedChunksPlugin",				chunks => {					const chunkGraph = compilation.chunkGraph;					// prepare two bit integers for each module					// 2^31 is the max number represented as SMI in v8					// we want the bits distributed this way:					// the bit 2^31 is pretty rar and only one module should get it					// so it has a probability of 1 / modulesCount					// the first bit (2^0) is the easiest and every module could get it					// if it doesn't get a better bit					// from bit 2^n to 2^(n+1) there is a probability of p					// so 1 / modulesCount == p^31					// <=> p = sqrt31(1 / modulesCount)					// so we use a modulo of 1 / sqrt31(1 / modulesCount)					/** @type {WeakMap<Module, number>} */					const moduleBits = new WeakMap();					const modulesCount = compilation.modules.size;					// precalculate the modulo values for each bit					const modulo = 1 / Math.pow(1 / modulesCount, 1 / 31);					const modulos = Array.from(						{ length: 31 },						(x, i) => Math.pow(modulo, i) | 0					);					// iterate all modules to generate bit values					let i = 0;					for (const module of compilation.modules) {						let bit = 30;						while (i % modulos[bit] !== 0) {							bit--;						}						moduleBits.set(module, 1 << bit);						i++;					}					// iterate all chunks to generate bitmaps					/** @type {WeakMap<Chunk, number>} */					const chunkModulesHash = new WeakMap();					for (const chunk of chunks) {						let hash = 0;						for (const module of chunkGraph.getChunkModulesIterable(chunk)) {							hash |= /** @type {number} */ (moduleBits.get(module));						}						chunkModulesHash.set(chunk, hash);					}					for (const chunkA of chunks) {						const chunkAHash =							/** @type {number} */							(chunkModulesHash.get(chunkA));						const chunkAModulesCount =							chunkGraph.getNumberOfChunkModules(chunkA);						if (chunkAModulesCount === 0) continue;						let bestModule = undefined;						for (const module of chunkGraph.getChunkModulesIterable(chunkA)) {							if (								bestModule === undefined ||								chunkGraph.getNumberOfModuleChunks(bestModule) >									chunkGraph.getNumberOfModuleChunks(module)							)								bestModule = module;						}						loopB: for (const chunkB of chunkGraph.getModuleChunksIterable(							/** @type {Module} */ (bestModule)						)) {							// as we iterate the same iterables twice							// skip if we find ourselves							if (chunkA === chunkB) continue;							const chunkBModulesCount =								chunkGraph.getNumberOfChunkModules(chunkB);							// ids for empty chunks are not included							if (chunkBModulesCount === 0) continue;							// instead of swapping A and B just bail							// as we loop twice the current A will be B and B then A							if (chunkAModulesCount > chunkBModulesCount) continue;							// is chunkA in chunkB?							// we do a cheap check for the hash value							const chunkBHash =								/** @type {number} */								(chunkModulesHash.get(chunkB));							if ((chunkBHash & chunkAHash) !== chunkAHash) continue;							// compare all modules							for (const m of chunkGraph.getChunkModulesIterable(chunkA)) {								if (!chunkGraph.isModuleInChunk(m, chunkB)) continue loopB;							}							/** @type {ChunkId[]} */							(chunkB.ids).push(/** @type {ChunkId} */ (chunkA.id));						}					}				}			);		});	}}module.exports = FlagIncludedChunksPlugin;
 |