| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-03 19:13:18 +08:00
										 |  |  | class RecordIdsPlugin { | 
					
						
							| 
									
										
										
										
											2017-12-01 16:49:07 +08:00
										 |  |  | 	constructor(options) { | 
					
						
							|  |  |  | 		this.options = options || {}; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-23 18:41:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											2017-12-01 16:49:07 +08:00
										 |  |  | 		const portableIds = this.options.portableIds; | 
					
						
							| 
									
										
										
										
											2017-12-06 22:01:25 +08:00
										 |  |  | 		compiler.hooks.compilation.tap("RecordIdsPlugin", (compilation) => { | 
					
						
							|  |  |  | 			compilation.hooks.recordModules.tap("RecordIdsPlugin", (modules, records) => { | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 				if(!records.modules) records.modules = {}; | 
					
						
							|  |  |  | 				if(!records.modules.byIdentifier) records.modules.byIdentifier = {}; | 
					
						
							|  |  |  | 				if(!records.modules.usedIds) records.modules.usedIds = {}; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 				modules.forEach(module => { | 
					
						
							| 
									
										
										
										
											2017-12-01 16:49:07 +08:00
										 |  |  | 					const identifier = portableIds ? identifierUtils.makePathsRelative(compiler.context, module.identifier(), compilation.cache) : module.identifier(); | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 					records.modules.byIdentifier[identifier] = module.id; | 
					
						
							|  |  |  | 					records.modules.usedIds[module.id] = module.id; | 
					
						
							| 
									
										
										
										
											2016-07-18 06:41:26 +08:00
										 |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-12-06 22:01:25 +08:00
										 |  |  | 			compilation.hooks.reviveModules.tap("RecordIdsPlugin", (modules, records) => { | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 				if(!records.modules) return; | 
					
						
							|  |  |  | 				if(records.modules.byIdentifier) { | 
					
						
							|  |  |  | 					const usedIds = {}; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 					modules.forEach(module => { | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 						if(module.id !== null) return; | 
					
						
							| 
									
										
										
										
											2017-12-01 16:49:07 +08:00
										 |  |  | 						const identifier = portableIds ? identifierUtils.makePathsRelative(compiler.context, module.identifier(), compilation.cache) : module.identifier(); | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 						const id = records.modules.byIdentifier[identifier]; | 
					
						
							|  |  |  | 						if(id === undefined) return; | 
					
						
							|  |  |  | 						if(usedIds[id]) return; | 
					
						
							|  |  |  | 						usedIds[id] = true; | 
					
						
							|  |  |  | 						module.id = id; | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				compilation.usedModuleIds = records.modules.usedIds; | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2015-04-24 05:55:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 			const getDepBlockIdent = (chunk, block) => { | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 				const ident = []; | 
					
						
							|  |  |  | 				if(block.chunks.length > 1) | 
					
						
							|  |  |  | 					ident.push(block.chunks.indexOf(chunk)); | 
					
						
							|  |  |  | 				while(block.parent) { | 
					
						
							|  |  |  | 					const p = block.parent; | 
					
						
							|  |  |  | 					const idx = p.blocks.indexOf(block); | 
					
						
							|  |  |  | 					const l = p.blocks.length - 1; | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 					ident.push(`${idx}/${l}`); | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 					block = block.parent; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if(!block.identifier) return null; | 
					
						
							| 
									
										
										
										
											2017-12-01 16:49:07 +08:00
										 |  |  | 				const identifier = portableIds ? identifierUtils.makePathsRelative(compiler.context, block.identifier(), compilation.cache) : block.identifier(); | 
					
						
							|  |  |  | 				ident.push(identifier); | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 				return ident.reverse().join(":"); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-06 22:01:25 +08:00
										 |  |  | 			compilation.hooks.recordChunks.tap("RecordIdsPlugin", (chunks, records) => { | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 				records.nextFreeChunkId = compilation.nextFreeChunkId; | 
					
						
							|  |  |  | 				if(!records.chunks) records.chunks = {}; | 
					
						
							|  |  |  | 				if(!records.chunks.byName) records.chunks.byName = {}; | 
					
						
							|  |  |  | 				if(!records.chunks.byBlocks) records.chunks.byBlocks = {}; | 
					
						
							|  |  |  | 				records.chunks.usedIds = {}; | 
					
						
							|  |  |  | 				chunks.forEach(chunk => { | 
					
						
							|  |  |  | 					const name = chunk.name; | 
					
						
							| 
									
										
										
										
											2017-09-22 22:38:47 +08:00
										 |  |  | 					const blockIdents = chunk.mapBlocks(getDepBlockIdent.bind(null, chunk)).filter(Boolean); | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 					if(name) records.chunks.byName[name] = chunk.id; | 
					
						
							|  |  |  | 					blockIdents.forEach((blockIdent) => { | 
					
						
							|  |  |  | 						records.chunks.byBlocks[blockIdent] = chunk.id; | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					records.chunks.usedIds[chunk.id] = chunk.id; | 
					
						
							| 
									
										
										
										
											2013-05-31 18:22:40 +08:00
										 |  |  | 				}); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-12-06 22:01:25 +08:00
										 |  |  | 			compilation.hooks.reviveChunks.tap("RecordIdsPlugin", (chunks, records) => { | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 				if(!records.chunks) return; | 
					
						
							|  |  |  | 				const usedIds = {}; | 
					
						
							|  |  |  | 				if(records.chunks.byName) { | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 					chunks.forEach(chunk => { | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 						if(chunk.id !== null) return; | 
					
						
							|  |  |  | 						if(!chunk.name) return; | 
					
						
							|  |  |  | 						const id = records.chunks.byName[chunk.name]; | 
					
						
							|  |  |  | 						if(id === undefined) return; | 
					
						
							|  |  |  | 						if(usedIds[id]) return; | 
					
						
							|  |  |  | 						usedIds[id] = true; | 
					
						
							|  |  |  | 						chunk.id = id; | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if(records.chunks.byBlocks) { | 
					
						
							|  |  |  | 					const argumentedChunks = chunks.filter(chunk => chunk.id === null).map(chunk => ({ | 
					
						
							|  |  |  | 						chunk, | 
					
						
							| 
									
										
										
										
											2017-09-22 22:38:47 +08:00
										 |  |  | 						blockIdents: chunk.mapBlocks(getDepBlockIdent.bind(null, chunk)).filter(Boolean) | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 					})).filter(arg => arg.blockIdents.length > 0); | 
					
						
							|  |  |  | 					let blockIdentsCount = {}; | 
					
						
							|  |  |  | 					argumentedChunks.forEach((arg, idx) => { | 
					
						
							|  |  |  | 						arg.blockIdents.forEach(blockIdent => { | 
					
						
							|  |  |  | 							const id = records.chunks.byBlocks[blockIdent]; | 
					
						
							|  |  |  | 							if(typeof id !== "number") return; | 
					
						
							|  |  |  | 							const accessor = `${id}:${idx}`; | 
					
						
							|  |  |  | 							blockIdentsCount[accessor] = (blockIdentsCount[accessor] || 0) + 1; | 
					
						
							|  |  |  | 						}); | 
					
						
							| 
									
										
										
										
											2013-05-31 18:22:40 +08:00
										 |  |  | 					}); | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 					blockIdentsCount = Object.keys(blockIdentsCount).map(accessor => [blockIdentsCount[accessor]].concat(accessor.split(":").map(Number))).sort((a, b) => b[0] - a[0]); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 					blockIdentsCount.forEach(arg => { | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 						const id = arg[1]; | 
					
						
							|  |  |  | 						if(usedIds[id]) return; | 
					
						
							|  |  |  | 						const idx = arg[2]; | 
					
						
							|  |  |  | 						const chunk = argumentedChunks[idx].chunk; | 
					
						
							|  |  |  | 						if(chunk.id !== null) return; | 
					
						
							|  |  |  | 						usedIds[id] = true; | 
					
						
							|  |  |  | 						chunk.id = id; | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				compilation.usedChunkIds = records.chunks.usedIds; | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2013-05-31 18:22:40 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-02-21 22:13:09 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports = RecordIdsPlugin; |