| 
									
										
										
										
											2013-05-31 18:22:40 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2015-04-04 08:09:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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("./Compiler")} Compiler */ | 
					
						
							|  |  |  | /** @typedef {import("./Chunk")} Chunk */ | 
					
						
							|  |  |  | /** @typedef {import("./Module")} Module */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} RecordsChunks | 
					
						
							|  |  |  |  * @property {Record<string, number>=} byName | 
					
						
							|  |  |  |  * @property {Record<string, number>=} bySource | 
					
						
							|  |  |  |  * @property {number[]=} usedIds | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} RecordsModules | 
					
						
							|  |  |  |  * @property {Record<string, number>=} byIdentifier | 
					
						
							|  |  |  |  * @property {Record<string, number>=} bySource | 
					
						
							|  |  |  |  * @property {Record<number, number>=} usedIds | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} Records | 
					
						
							|  |  |  |  * @property {RecordsChunks=} chunks | 
					
						
							|  |  |  |  * @property {RecordsModules=} modules | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-03 19:13:18 +08:00
										 |  |  | class RecordIdsPlugin { | 
					
						
							| 
									
										
										
										
											2018-06-06 22:37:23 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Object} options Options object | 
					
						
							|  |  |  | 	 * @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; | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * @param {Module[]} modules the modules array | 
					
						
							|  |  |  | 				 * @param {Records} records the records object | 
					
						
							|  |  |  | 				 * @returns {void} | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				(modules, records) => { | 
					
						
							|  |  |  | 					if (!records.modules) records.modules = {}; | 
					
						
							|  |  |  | 					if (!records.modules.byIdentifier) records.modules.byIdentifier = {}; | 
					
						
							|  |  |  | 					if (!records.modules.usedIds) records.modules.usedIds = {}; | 
					
						
							|  |  |  | 					for (const module of modules) { | 
					
						
							| 
									
										
										
										
											2018-05-24 22:07:19 +08:00
										 |  |  | 						if (typeof module.id !== "number") continue; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						const identifier = portableIds | 
					
						
							|  |  |  | 							? identifierUtils.makePathsRelative( | 
					
						
							|  |  |  | 									compiler.context, | 
					
						
							|  |  |  | 									module.identifier(), | 
					
						
							|  |  |  | 									compilation.cache | 
					
						
							| 
									
										
										
										
											2018-03-26 22:56:10 +08:00
										 |  |  | 							  ) | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							: module.identifier(); | 
					
						
							|  |  |  | 						records.modules.byIdentifier[identifier] = module.id; | 
					
						
							|  |  |  | 						records.modules.usedIds[module.id] = module.id; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * @param {Module[]} modules the modules array | 
					
						
							|  |  |  | 				 * @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-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) { | 
					
						
							|  |  |  | 							if (module.id !== null) continue; | 
					
						
							|  |  |  | 							const identifier = portableIds | 
					
						
							|  |  |  | 								? identifierUtils.makePathsRelative( | 
					
						
							|  |  |  | 										compiler.context, | 
					
						
							|  |  |  | 										module.identifier(), | 
					
						
							|  |  |  | 										compilation.cache | 
					
						
							| 
									
										
										
										
											2018-03-26 22:56:10 +08:00
										 |  |  | 								  ) | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								: module.identifier(); | 
					
						
							|  |  |  | 							const id = records.modules.byIdentifier[identifier]; | 
					
						
							|  |  |  | 							if (id === undefined) continue; | 
					
						
							|  |  |  | 							if (usedIds.has(id)) continue; | 
					
						
							|  |  |  | 							usedIds.add(id); | 
					
						
							|  |  |  | 							module.id = id; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											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 {Module} module the module | 
					
						
							|  |  |  | 			 * @returns {string} the (portable) identifier | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			const getModuleIdentifier = module => { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				if (portableIds) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return identifierUtils.makePathsRelative( | 
					
						
							|  |  |  | 						compiler.context, | 
					
						
							|  |  |  | 						module.identifier(), | 
					
						
							|  |  |  | 						compilation.cache | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 				return module.identifier(); | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					for (const origin of chunkGroup.origins) { | 
					
						
							|  |  |  | 						if (origin.module) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 							if (origin.request) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								sources.push( | 
					
						
							|  |  |  | 									`${index} ${getModuleIdentifier(origin.module)} ${ | 
					
						
							|  |  |  | 										origin.request | 
					
						
							|  |  |  | 									}`
 | 
					
						
							|  |  |  | 								); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 							} else if (typeof origin.loc === "string") { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								sources.push( | 
					
						
							|  |  |  | 									`${index} ${getModuleIdentifier(origin.module)} ${origin.loc}` | 
					
						
							|  |  |  | 								); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 							} else if ( | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								origin.loc && | 
					
						
							|  |  |  | 								typeof origin.loc === "object" && | 
					
						
							| 
									
										
										
										
											2018-07-23 18:19:16 +08:00
										 |  |  | 								"start" in origin.loc | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 							) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 								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
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * @param {Chunk[]} chunks the chunks array | 
					
						
							|  |  |  | 				 * @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-05-21 22:45:28 +08:00
										 |  |  | 					records.chunks.usedIds = Array.from(usedIds).sort(); | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * @param {Chunk[]} chunks the chunks array | 
					
						
							|  |  |  | 				 * @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-01-22 20:52:43 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (records.chunks.bySource) { | 
					
						
							|  |  |  | 						for (const chunk of chunks) { | 
					
						
							|  |  |  | 							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; | 
					
						
							|  |  |  | 								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; |