| 
									
										
										
										
											2013-02-24 09:05:55 +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 06:23:48 +08:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-09 05:59:19 +08:00
										 |  |  | /** @typedef {import("../Chunk")} Chunk */ | 
					
						
							|  |  |  | /** @typedef {import("../Compiler")} Compiler */ | 
					
						
							|  |  |  | /** @typedef {import("../Module")} Module */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-05 06:23:48 +08:00
										 |  |  | class FlagIncludedChunksPlugin { | 
					
						
							| 
									
										
										
										
											2018-11-09 05:59:19 +08:00
										 |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2020-04-23 16:48:36 +08:00
										 |  |  | 	 * Apply the plugin | 
					
						
							| 
									
										
										
										
											2018-11-09 05:59:19 +08:00
										 |  |  | 	 * @param {Compiler} compiler the compiler instance | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-01-05 06:23:48 +08:00
										 |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		compiler.hooks.compilation.tap("FlagIncludedChunksPlugin", compilation => { | 
					
						
							|  |  |  | 			compilation.hooks.optimizeChunkIds.tap( | 
					
						
							|  |  |  | 				"FlagIncludedChunksPlugin", | 
					
						
							|  |  |  | 				chunks => { | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 					const chunkGraph = compilation.chunkGraph; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 					// 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)
 | 
					
						
							| 
									
										
										
										
											2018-11-09 05:59:19 +08:00
										 |  |  | 					/** @type {WeakMap<Module, number>} */ | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 					const moduleBits = new WeakMap(); | 
					
						
							| 
									
										
										
										
											2018-09-05 22:12:48 +08:00
										 |  |  | 					const modulesCount = compilation.modules.size; | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					// 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++; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:51:26 +08:00
										 |  |  | 					// iterate all chunks to generate bitmaps
 | 
					
						
							| 
									
										
										
										
											2018-11-09 05:59:19 +08:00
										 |  |  | 					/** @type {WeakMap<Chunk, number>} */ | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 					const chunkModulesHash = new WeakMap(); | 
					
						
							|  |  |  | 					for (const chunk of chunks) { | 
					
						
							|  |  |  | 						let hash = 0; | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 						for (const module of chunkGraph.getChunkModulesIterable(chunk)) { | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 							hash |= moduleBits.get(module); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						chunkModulesHash.set(chunk, hash); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					for (const chunkA of chunks) { | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 						const chunkAHash = chunkModulesHash.get(chunkA); | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 						const chunkAModulesCount = chunkGraph.getNumberOfChunkModules( | 
					
						
							|  |  |  | 							chunkA | 
					
						
							|  |  |  | 						); | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 						if (chunkAModulesCount === 0) continue; | 
					
						
							|  |  |  | 						let bestModule = undefined; | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 						for (const module of chunkGraph.getChunkModulesIterable(chunkA)) { | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 							if ( | 
					
						
							|  |  |  | 								bestModule === undefined || | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 								chunkGraph.getNumberOfModuleChunks(bestModule) > | 
					
						
							|  |  |  | 									chunkGraph.getNumberOfModuleChunks(module) | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 							) | 
					
						
							|  |  |  | 								bestModule = module; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 						loopB: for (const chunkB of chunkGraph.getModuleChunksIterable( | 
					
						
							|  |  |  | 							bestModule | 
					
						
							|  |  |  | 						)) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							// as we iterate the same iterables twice
 | 
					
						
							|  |  |  | 							// skip if we find ourselves
 | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 							if (chunkA === chunkB) continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 							const chunkBModulesCount = chunkGraph.getNumberOfChunkModules( | 
					
						
							|  |  |  | 								chunkB | 
					
						
							|  |  |  | 							); | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							// ids for empty chunks are not included
 | 
					
						
							|  |  |  | 							if (chunkBModulesCount === 0) continue; | 
					
						
							| 
									
										
										
										
											2017-02-23 20:39:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							// instead of swapping A and B just bail
 | 
					
						
							|  |  |  | 							// as we loop twice the current A will be B and B then A
 | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 							if (chunkAModulesCount > chunkBModulesCount) continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// is chunkA in chunkB?
 | 
					
						
							| 
									
										
										
										
											2017-02-23 20:39:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 							// we do a cheap check for the hash value
 | 
					
						
							|  |  |  | 							const chunkBHash = chunkModulesHash.get(chunkB); | 
					
						
							|  |  |  | 							if ((chunkBHash & chunkAHash) !== chunkAHash) continue; | 
					
						
							| 
									
										
										
										
											2017-03-18 09:20:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 							// compare all modules
 | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 							for (const m of chunkGraph.getChunkModulesIterable(chunkA)) { | 
					
						
							|  |  |  | 								if (!chunkGraph.isModuleInChunk(m, chunkB)) continue loopB; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-04-27 20:24:08 +08:00
										 |  |  | 							chunkB.ids.push(chunkA.id); | 
					
						
							| 
									
										
										
										
											2017-01-05 06:23:48 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-01-22 20:52:43 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			); | 
					
						
							| 
									
										
										
										
											2013-02-24 09:05:55 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-01-05 06:23:48 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports = FlagIncludedChunksPlugin; |