| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";class FlagIncludedChunksPlugin {	apply(compiler) {		compiler.hooks.compilation.tap("FlagIncludedChunksPlugin", compilation => {			compilation.hooks.optimizeChunkIds.tap(				"FlagIncludedChunksPlugin",				chunks => {					// 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)					const moduleBits = new WeakMap();					const modulesCount = compilation.modules.length;					// 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++;					}					// interate all chunks to generate bitmaps					const chunkModulesHash = new WeakMap();					for (const chunk of chunks) {						let hash = 0;						for (const module of chunk.modulesIterable) {							hash |= moduleBits.get(module);						}						chunkModulesHash.set(chunk, hash);					}					for (const chunkA of chunks) {						const chunkAHash = chunkModulesHash.get(chunkA);						const chunkAModulesCount = chunkA.getNumberOfModules();						if (chunkAModulesCount === 0) continue;						let bestModule = undefined;						for (const module of chunkA.modulesIterable) {							if (								bestModule === undefined ||								bestModule.getNumberOfChunks() > module.getNumberOfChunks()							)								bestModule = module;						}						loopB: for (const chunkB of bestModule.chunksIterable) {							// as we iterate the same iterables twice							// skip if we find ourselves							if (chunkA === chunkB) continue;							const chunkBModulesCount = chunkB.getNumberOfModules();							// 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 = chunkModulesHash.get(chunkB);							if ((chunkBHash & chunkAHash) !== chunkAHash) continue;							// compare all modules							for (const m of chunkA.modulesIterable) {								if (!chunkB.containsModule(m)) continue loopB;							}							chunkB.ids.push(chunkA.id);						}					}				}			);		});	}}module.exports = FlagIncludedChunksPlugin;
 |