You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							236 lines
						
					
					
						
							6.5 KiB
						
					
					
				
			
		
		
	
	
							236 lines
						
					
					
						
							6.5 KiB
						
					
					
				/* | 
						|
	MIT License http://www.opensource.org/licenses/mit-license.php | 
						|
	Author Tobias Koppers @sokra | 
						|
*/ | 
						|
"use strict"; | 
						|
 | 
						|
const identifierUtils = require("./util/identifier"); | 
						|
 | 
						|
/** @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 | 
						|
 */ | 
						|
 | 
						|
class RecordIdsPlugin { | 
						|
	/** | 
						|
	 * @param {Object} options Options object | 
						|
	 * @param {boolean=} options.portableIds true, when ids need to be portable | 
						|
	 */ | 
						|
	constructor(options) { | 
						|
		this.options = options || {}; | 
						|
	} | 
						|
 | 
						|
	/** | 
						|
	 * @param {Compiler} compiler the Compiler | 
						|
	 * @returns {void} | 
						|
	 */ | 
						|
	apply(compiler) { | 
						|
		const portableIds = this.options.portableIds; | 
						|
		compiler.hooks.compilation.tap("RecordIdsPlugin", compilation => { | 
						|
			compilation.hooks.recordModules.tap( | 
						|
				"RecordIdsPlugin", | 
						|
				/** | 
						|
				 * @param {Module[]} modules the modules array | 
						|
				 * @param {Records} records the records object | 
						|
				 * @returns {void} | 
						|
				 */ | 
						|
				(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) { | 
						|
						if (typeof module.id !== "number") continue; | 
						|
						const identifier = portableIds | 
						|
							? identifierUtils.makePathsRelative( | 
						|
									compiler.context, | 
						|
									module.identifier(), | 
						|
									compilation.cache | 
						|
							  ) | 
						|
							: module.identifier(); | 
						|
						records.modules.byIdentifier[identifier] = module.id; | 
						|
						records.modules.usedIds[module.id] = module.id; | 
						|
					} | 
						|
				} | 
						|
			); | 
						|
			compilation.hooks.reviveModules.tap( | 
						|
				"RecordIdsPlugin", | 
						|
				/** | 
						|
				 * @param {Module[]} modules the modules array | 
						|
				 * @param {Records} records the records object | 
						|
				 * @returns {void} | 
						|
				 */ | 
						|
				(modules, records) => { | 
						|
					if (!records.modules) return; | 
						|
					if (records.modules.byIdentifier) { | 
						|
						/** @type {Set<number>} */ | 
						|
						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 | 
						|
								  ) | 
						|
								: module.identifier(); | 
						|
							const id = records.modules.byIdentifier[identifier]; | 
						|
							if (id === undefined) continue; | 
						|
							if (usedIds.has(id)) continue; | 
						|
							usedIds.add(id); | 
						|
							module.id = id; | 
						|
						} | 
						|
					} | 
						|
					if (Array.isArray(records.modules.usedIds)) { | 
						|
						compilation.usedModuleIds = new Set(records.modules.usedIds); | 
						|
					} | 
						|
				} | 
						|
			); | 
						|
 | 
						|
			/** | 
						|
			 * @param {Module} module the module | 
						|
			 * @returns {string} the (portable) identifier | 
						|
			 */ | 
						|
			const getModuleIdentifier = module => { | 
						|
				if (portableIds) { | 
						|
					return identifierUtils.makePathsRelative( | 
						|
						compiler.context, | 
						|
						module.identifier(), | 
						|
						compilation.cache | 
						|
					); | 
						|
				} | 
						|
				return module.identifier(); | 
						|
			}; | 
						|
 | 
						|
			/** | 
						|
			 * @param {Chunk} chunk the chunk | 
						|
			 * @returns {string[]} sources of the chunk | 
						|
			 */ | 
						|
			const getChunkSources = chunk => { | 
						|
				/** @type {string[]} */ | 
						|
				const sources = []; | 
						|
				for (const chunkGroup of chunk.groupsIterable) { | 
						|
					const index = chunkGroup.chunks.indexOf(chunk); | 
						|
					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" && | 
						|
									origin.loc.start | 
						|
								) { | 
						|
									sources.push( | 
						|
										`${index} ${getModuleIdentifier( | 
						|
											origin.module | 
						|
										)} ${JSON.stringify(origin.loc.start)}` | 
						|
									); | 
						|
								} | 
						|
							} | 
						|
						} | 
						|
					} | 
						|
				} | 
						|
				return sources; | 
						|
			}; | 
						|
 | 
						|
			compilation.hooks.recordChunks.tap( | 
						|
				"RecordIdsPlugin", | 
						|
				/** | 
						|
				 * @param {Chunk[]} chunks the chunks array | 
						|
				 * @param {Records} records the records object | 
						|
				 * @returns {void} | 
						|
				 */ | 
						|
				(chunks, records) => { | 
						|
					if (!records.chunks) records.chunks = {}; | 
						|
					if (!records.chunks.byName) records.chunks.byName = {}; | 
						|
					if (!records.chunks.bySource) records.chunks.bySource = {}; | 
						|
					/** @type {Set<number>} */ | 
						|
					const usedIds = new Set(); | 
						|
					for (const chunk of chunks) { | 
						|
						if (typeof chunk.id !== "number") continue; | 
						|
						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); | 
						|
					} | 
						|
					records.chunks.usedIds = Array.from(usedIds).sort(); | 
						|
				} | 
						|
			); | 
						|
			compilation.hooks.reviveChunks.tap( | 
						|
				"RecordIdsPlugin", | 
						|
				/** | 
						|
				 * @param {Chunk[]} chunks the chunks array | 
						|
				 * @param {Records} records the records object | 
						|
				 * @returns {void} | 
						|
				 */ | 
						|
				(chunks, records) => { | 
						|
					if (!records.chunks) return; | 
						|
					/** @type {Set<number>} */ | 
						|
					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); | 
						|
							chunk.id = id; | 
						|
						} | 
						|
					} | 
						|
					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; | 
						|
								if (usedIds.has(id)) continue; | 
						|
								usedIds.add(id); | 
						|
								chunk.id = id; | 
						|
								break; | 
						|
							} | 
						|
						} | 
						|
					} | 
						|
					if (Array.isArray(records.chunks.usedIds)) { | 
						|
						compilation.usedChunkIds = new Set(records.chunks.usedIds); | 
						|
					} | 
						|
				} | 
						|
			); | 
						|
		}); | 
						|
	} | 
						|
} | 
						|
module.exports = RecordIdsPlugin;
 | 
						|
 |