| 
									
										
										
										
											2013-05-31 18:22:40 +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-02-21 22:13:09 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2015-04-04 08:09:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-05 22:08:09 +08:00
										 |  |  | const { compareNumbers } = require("./util/comparators"); | 
					
						
							| 
									
										
										
										
											2017-04-05 21:38:15 +08:00
										 |  |  | const identifierUtils = require("./util/identifier"); | 
					
						
							| 
									
										
										
										
											2017-03-23 18:41:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | /** @typedef {import("./Chunk")} Chunk */ | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | /** @typedef {import("./Compiler")} Compiler */ | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | /** @typedef {import("./Module")} Module */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-06-11 21:09:50 +08:00
										 |  |  |  * @typedef {object} RecordsChunks | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  |  * @property {Record<string, number>=} byName | 
					
						
							|  |  |  |  * @property {Record<string, number>=} bySource | 
					
						
							|  |  |  |  * @property {number[]=} usedIds | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-06-11 21:09:50 +08:00
										 |  |  |  * @typedef {object} RecordsModules | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  |  * @property {Record<string, number>=} byIdentifier | 
					
						
							|  |  |  |  * @property {Record<string, number>=} bySource | 
					
						
							| 
									
										
										
										
											2018-09-05 22:08:09 +08:00
										 |  |  |  * @property {number[]=} usedIds | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-06-11 21:09:50 +08:00
										 |  |  |  * @typedef {object} Records | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  |  * @property {RecordsChunks=} chunks | 
					
						
							|  |  |  |  * @property {RecordsModules=} modules | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-03 19:13:18 +08:00
										 |  |  | class RecordIdsPlugin { | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2024-06-11 21:09:50 +08:00
										 |  |  | 	 * @param {object} options Options object | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 	 * @param {boolean=} options.portableIds true, when ids need to be portable | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-12-01 16:49:07 +08:00
										 |  |  | 	constructor(options) { | 
					
						
							|  |  |  | 		this.options = options || {}; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-23 18:41:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Compiler} compiler the Compiler | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											2017-12-01 16:49:07 +08:00
										 |  |  | 		const portableIds = this.options.portableIds; | 
					
						
							| 
									
										
										
										
											2020-04-17 16:54:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-11 15:31:46 +08:00
										 |  |  | 		const makePathsRelative = | 
					
						
							|  |  |  | 			identifierUtils.makePathsRelative.bindContextCache( | 
					
						
							|  |  |  | 				compiler.context, | 
					
						
							|  |  |  | 				compiler.root | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2020-04-17 16:54:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @param {Module} module the module | 
					
						
							|  |  |  | 		 * @returns {string} the (portable) identifier | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		const getModuleIdentifier = module => { | 
					
						
							|  |  |  | 			if (portableIds) { | 
					
						
							|  |  |  | 				return makePathsRelative(module.identifier()); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return module.identifier(); | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		compiler.hooks.compilation.tap("RecordIdsPlugin", compilation => { | 
					
						
							|  |  |  | 			compilation.hooks.recordModules.tap( | 
					
						
							|  |  |  | 				"RecordIdsPlugin", | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 				/** | 
					
						
							| 
									
										
										
										
											2023-05-25 03:37:58 +08:00
										 |  |  | 				 * @param {Iterable<Module>} modules the modules array | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 				 * @param {Records} records the records object | 
					
						
							|  |  |  | 				 * @returns {void} | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				(modules, records) => { | 
					
						
							| 
									
										
										
										
											2018-08-28 17:56:48 +08:00
										 |  |  | 					const chunkGraph = compilation.chunkGraph; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (!records.modules) records.modules = {}; | 
					
						
							|  |  |  | 					if (!records.modules.byIdentifier) records.modules.byIdentifier = {}; | 
					
						
							| 
									
										
										
										
											2018-09-05 22:08:09 +08:00
										 |  |  | 					/** @type {Set<number>} */ | 
					
						
							|  |  |  | 					const usedIds = new Set(); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					for (const module of modules) { | 
					
						
							| 
									
										
										
										
											2018-08-28 17:56:48 +08:00
										 |  |  | 						const moduleId = chunkGraph.getModuleId(module); | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 						if (typeof moduleId !== "number") continue; | 
					
						
							| 
									
										
										
										
											2020-04-17 16:54:27 +08:00
										 |  |  | 						const identifier = getModuleIdentifier(module); | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 						records.modules.byIdentifier[identifier] = moduleId; | 
					
						
							| 
									
										
										
										
											2018-09-05 22:08:09 +08:00
										 |  |  | 						usedIds.add(moduleId); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-09-05 22:08:09 +08:00
										 |  |  | 					records.modules.usedIds = Array.from(usedIds).sort(compareNumbers); | 
					
						
							| 
									
										
										
										
											2018-01-22 20:52:43 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			); | 
					
						
							|  |  |  | 			compilation.hooks.reviveModules.tap( | 
					
						
							|  |  |  | 				"RecordIdsPlugin", | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 				/** | 
					
						
							| 
									
										
										
										
											2023-05-25 03:37:58 +08:00
										 |  |  | 				 * @param {Iterable<Module>} modules the modules array | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 				 * @param {Records} records the records object | 
					
						
							|  |  |  | 				 * @returns {void} | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				(modules, records) => { | 
					
						
							|  |  |  | 					if (!records.modules) return; | 
					
						
							|  |  |  | 					if (records.modules.byIdentifier) { | 
					
						
							| 
									
										
										
										
											2018-08-28 17:56:48 +08:00
										 |  |  | 						const chunkGraph = compilation.chunkGraph; | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 						/** @type {Set<number>} */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						const usedIds = new Set(); | 
					
						
							|  |  |  | 						for (const module of modules) { | 
					
						
							| 
									
										
										
										
											2018-08-28 17:56:48 +08:00
										 |  |  | 							const moduleId = chunkGraph.getModuleId(module); | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 							if (moduleId !== null) continue; | 
					
						
							| 
									
										
										
										
											2020-04-17 16:54:27 +08:00
										 |  |  | 							const identifier = getModuleIdentifier(module); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							const id = records.modules.byIdentifier[identifier]; | 
					
						
							|  |  |  | 							if (id === undefined) continue; | 
					
						
							|  |  |  | 							if (usedIds.has(id)) continue; | 
					
						
							|  |  |  | 							usedIds.add(id); | 
					
						
							| 
									
										
										
										
											2018-08-28 17:56:48 +08:00
										 |  |  | 							chunkGraph.setModuleId(module, id); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-01-22 20:52:43 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					if (Array.isArray(records.modules.usedIds)) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						compilation.usedModuleIds = new Set(records.modules.usedIds); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			); | 
					
						
							| 
									
										
										
										
											2015-04-24 05:55:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 			/** | 
					
						
							|  |  |  | 			 * @param {Chunk} chunk the chunk | 
					
						
							|  |  |  | 			 * @returns {string[]} sources of the chunk | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			const getChunkSources = chunk => { | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 				/** @type {string[]} */ | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 				const sources = []; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				for (const chunkGroup of chunk.groupsIterable) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 					const index = chunkGroup.chunks.indexOf(chunk); | 
					
						
							| 
									
										
										
										
											2020-04-25 06:28:27 +08:00
										 |  |  | 					if (chunkGroup.name) { | 
					
						
							|  |  |  | 						sources.push(`${index} ${chunkGroup.name}`); | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						for (const origin of chunkGroup.origins) { | 
					
						
							|  |  |  | 							if (origin.module) { | 
					
						
							|  |  |  | 								if (origin.request) { | 
					
						
							|  |  |  | 									sources.push( | 
					
						
							|  |  |  | 										`${index} ${getModuleIdentifier(origin.module)} ${ | 
					
						
							|  |  |  | 											origin.request | 
					
						
							|  |  |  | 										}`
 | 
					
						
							|  |  |  | 									); | 
					
						
							|  |  |  | 								} else if (typeof origin.loc === "string") { | 
					
						
							|  |  |  | 									sources.push( | 
					
						
							|  |  |  | 										`${index} ${getModuleIdentifier(origin.module)} ${ | 
					
						
							|  |  |  | 											origin.loc | 
					
						
							|  |  |  | 										}`
 | 
					
						
							|  |  |  | 									); | 
					
						
							|  |  |  | 								} else if ( | 
					
						
							|  |  |  | 									origin.loc && | 
					
						
							|  |  |  | 									typeof origin.loc === "object" && | 
					
						
							|  |  |  | 									"start" in origin.loc | 
					
						
							|  |  |  | 								) { | 
					
						
							|  |  |  | 									sources.push( | 
					
						
							|  |  |  | 										`${index} ${getModuleIdentifier( | 
					
						
							|  |  |  | 											origin.module | 
					
						
							|  |  |  | 										)} ${JSON.stringify(origin.loc.start)}`
 | 
					
						
							|  |  |  | 									); | 
					
						
							|  |  |  | 								} | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 				return sources; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			compilation.hooks.recordChunks.tap( | 
					
						
							|  |  |  | 				"RecordIdsPlugin", | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 				/** | 
					
						
							| 
									
										
										
										
											2023-05-25 03:37:58 +08:00
										 |  |  | 				 * @param {Iterable<Chunk>} chunks the chunks array | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 				 * @param {Records} records the records object | 
					
						
							|  |  |  | 				 * @returns {void} | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				(chunks, records) => { | 
					
						
							|  |  |  | 					if (!records.chunks) records.chunks = {}; | 
					
						
							|  |  |  | 					if (!records.chunks.byName) records.chunks.byName = {}; | 
					
						
							|  |  |  | 					if (!records.chunks.bySource) records.chunks.bySource = {}; | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 					/** @type {Set<number>} */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					const usedIds = new Set(); | 
					
						
							|  |  |  | 					for (const chunk of chunks) { | 
					
						
							| 
									
										
										
										
											2018-05-24 22:07:19 +08:00
										 |  |  | 						if (typeof chunk.id !== "number") continue; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						const name = chunk.name; | 
					
						
							|  |  |  | 						if (name) records.chunks.byName[name] = chunk.id; | 
					
						
							|  |  |  | 						const sources = getChunkSources(chunk); | 
					
						
							|  |  |  | 						for (const source of sources) { | 
					
						
							|  |  |  | 							records.chunks.bySource[source] = chunk.id; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						usedIds.add(chunk.id); | 
					
						
							| 
									
										
										
										
											2018-01-22 20:52:43 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-09-05 22:08:09 +08:00
										 |  |  | 					records.chunks.usedIds = Array.from(usedIds).sort(compareNumbers); | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			); | 
					
						
							|  |  |  | 			compilation.hooks.reviveChunks.tap( | 
					
						
							|  |  |  | 				"RecordIdsPlugin", | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 				/** | 
					
						
							| 
									
										
										
										
											2023-05-25 03:37:58 +08:00
										 |  |  | 				 * @param {Iterable<Chunk>} chunks the chunks array | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 				 * @param {Records} records the records object | 
					
						
							|  |  |  | 				 * @returns {void} | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				(chunks, records) => { | 
					
						
							|  |  |  | 					if (!records.chunks) return; | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 					/** @type {Set<number>} */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					const usedIds = new Set(); | 
					
						
							|  |  |  | 					if (records.chunks.byName) { | 
					
						
							|  |  |  | 						for (const chunk of chunks) { | 
					
						
							|  |  |  | 							if (chunk.id !== null) continue; | 
					
						
							|  |  |  | 							if (!chunk.name) continue; | 
					
						
							|  |  |  | 							const id = records.chunks.byName[chunk.name]; | 
					
						
							|  |  |  | 							if (id === undefined) continue; | 
					
						
							|  |  |  | 							if (usedIds.has(id)) continue; | 
					
						
							|  |  |  | 							usedIds.add(id); | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 							chunk.id = id; | 
					
						
							| 
									
										
										
										
											2018-09-05 20:22:10 +08:00
										 |  |  | 							chunk.ids = [id]; | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-01-22 20:52:43 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (records.chunks.bySource) { | 
					
						
							|  |  |  | 						for (const chunk of chunks) { | 
					
						
							| 
									
										
										
										
											2021-03-19 22:57:40 +08:00
										 |  |  | 							if (chunk.id !== null) continue; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							const sources = getChunkSources(chunk); | 
					
						
							|  |  |  | 							for (const source of sources) { | 
					
						
							|  |  |  | 								const id = records.chunks.bySource[source]; | 
					
						
							|  |  |  | 								if (id === undefined) continue; | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 								if (usedIds.has(id)) continue; | 
					
						
							|  |  |  | 								usedIds.add(id); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								chunk.id = id; | 
					
						
							| 
									
										
										
										
											2018-09-05 20:22:10 +08:00
										 |  |  | 								chunk.ids = [id]; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								break; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					if (Array.isArray(records.chunks.usedIds)) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						compilation.usedChunkIds = new Set(records.chunks.usedIds); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			); | 
					
						
							| 
									
										
										
										
											2013-05-31 18:22:40 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports = RecordIdsPlugin; |