| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Jason Anderson @diurnalist | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | const REGEXP_HASH = /\[hash(?::(\d+))?\]/gi, | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 	REGEXP_CHUNKHASH = /\[chunkhash(?::(\d+))?\]/gi, | 
					
						
							| 
									
										
										
										
											2017-10-30 20:56:57 +08:00
										 |  |  | 	REGEXP_MODULEHASH = /\[modulehash(?::(\d+))?\]/gi, | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 	REGEXP_NAME = /\[name\]/gi, | 
					
						
							|  |  |  | 	REGEXP_ID = /\[id\]/gi, | 
					
						
							| 
									
										
										
										
											2017-10-30 20:56:57 +08:00
										 |  |  | 	REGEXP_MODULEID = /\[moduleid\]/gi, | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 	REGEXP_FILE = /\[file\]/gi, | 
					
						
							|  |  |  | 	REGEXP_QUERY = /\[query\]/gi, | 
					
						
							|  |  |  | 	REGEXP_FILEBASE = /\[filebase\]/gi; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-24 05:24:49 +08:00
										 |  |  | // Using global RegExp for .test is dangerous
 | 
					
						
							|  |  |  | // We use a normal RegExp instead of .test
 | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | const REGEXP_HASH_FOR_TEST = new RegExp(REGEXP_HASH.source, "i"), | 
					
						
							| 
									
										
										
										
											2014-09-24 05:24:49 +08:00
										 |  |  | 	REGEXP_CHUNKHASH_FOR_TEST = new RegExp(REGEXP_CHUNKHASH.source, "i"), | 
					
						
							|  |  |  | 	REGEXP_NAME_FOR_TEST = new RegExp(REGEXP_NAME.source, "i"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | const withHashLength = (replacer, handlerFn) => { | 
					
						
							| 
									
										
										
										
											2017-11-09 03:49:41 +08:00
										 |  |  | 	const fn = (match, hashLength, ...args) => { | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | 		const length = hashLength && parseInt(hashLength, 10); | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 		if(length && handlerFn) { | 
					
						
							| 
									
										
										
										
											2014-09-12 01:25:18 +08:00
										 |  |  | 			return handlerFn(length); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		const hash = replacer(match, hashLength, ...args); | 
					
						
							| 
									
										
										
										
											2014-09-12 01:25:18 +08:00
										 |  |  | 		return length ? hash.slice(0, length) : hash; | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2017-11-09 03:49:41 +08:00
										 |  |  | 	return fn; | 
					
						
							| 
									
										
										
										
											2017-01-11 17:51:58 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | const getReplacer = (value, allowEmpty) => { | 
					
						
							| 
									
										
										
										
											2017-11-09 03:49:41 +08:00
										 |  |  | 	const fn = (match, ...args) => { | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 		// last argument in replacer is the entire input string
 | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		const input = args[args.length - 1]; | 
					
						
							| 
									
										
										
										
											2017-01-11 17:51:58 +08:00
										 |  |  | 		if(value === null || value === undefined) { | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | 			if(!allowEmpty) throw new Error(`Path variable ${match} not implemented in this context: ${input}`); | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 			return ""; | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | 			return `${value}`; | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2017-11-09 03:49:41 +08:00
										 |  |  | 	return fn; | 
					
						
							| 
									
										
										
										
											2017-01-11 17:51:58 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | const replacePathVariables = (path, data) => { | 
					
						
							|  |  |  | 	const chunk = data.chunk; | 
					
						
							|  |  |  | 	const chunkId = chunk && chunk.id; | 
					
						
							|  |  |  | 	const chunkName = chunk && (chunk.name || chunk.id); | 
					
						
							|  |  |  | 	const chunkHash = chunk && (chunk.renderedHash || chunk.hash); | 
					
						
							|  |  |  | 	const chunkHashWithLength = chunk && chunk.hashWithLength; | 
					
						
							| 
									
										
										
										
											2017-10-30 20:56:57 +08:00
										 |  |  | 	const module = data.module; | 
					
						
							|  |  |  | 	const moduleId = module && module.id; | 
					
						
							|  |  |  | 	const moduleHash = module && (module.renderedHash || module.hash); | 
					
						
							|  |  |  | 	const moduleHashWithLength = module && module.hashWithLength; | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-20 10:03:15 +08:00
										 |  |  | 	if(typeof path === "function") { | 
					
						
							|  |  |  | 		path = path(data); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 	if(data.noChunkHash && REGEXP_CHUNKHASH_FOR_TEST.test(path)) { | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | 		throw new Error(`Cannot use [chunkhash] for chunk in '${path}' (use [hash] instead)`); | 
					
						
							| 
									
										
										
										
											2015-06-27 17:34:17 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 	return path | 
					
						
							| 
									
										
										
										
											2014-10-28 18:51:18 +08:00
										 |  |  | 		.replace(REGEXP_HASH, withHashLength(getReplacer(data.hash), data.hashWithLength)) | 
					
						
							| 
									
										
										
										
											2014-09-12 01:25:18 +08:00
										 |  |  | 		.replace(REGEXP_CHUNKHASH, withHashLength(getReplacer(chunkHash), chunkHashWithLength)) | 
					
						
							| 
									
										
										
										
											2017-10-30 20:56:57 +08:00
										 |  |  | 		.replace(REGEXP_MODULEHASH, withHashLength(getReplacer(moduleHash), moduleHashWithLength)) | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 		.replace(REGEXP_ID, getReplacer(chunkId)) | 
					
						
							| 
									
										
										
										
											2017-10-30 20:56:57 +08:00
										 |  |  | 		.replace(REGEXP_MODULEID, getReplacer(moduleId)) | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 		.replace(REGEXP_NAME, getReplacer(chunkName)) | 
					
						
							|  |  |  | 		.replace(REGEXP_FILE, getReplacer(data.filename)) | 
					
						
							|  |  |  | 		.replace(REGEXP_FILEBASE, getReplacer(data.basename)) | 
					
						
							|  |  |  | 		// query is optional, it's OK if it's in a path but there's nothing to replace it with
 | 
					
						
							|  |  |  | 		.replace(REGEXP_QUERY, getReplacer(data.query, true)); | 
					
						
							| 
									
										
										
										
											2017-01-11 17:51:58 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | class TemplatedPathPlugin { | 
					
						
							|  |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											2017-12-06 22:01:25 +08:00
										 |  |  | 		compiler.hooks.compilation.tap("TemplatedPathPlugin", (compilation) => { | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | 			const mainTemplate = compilation.mainTemplate; | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-14 04:35:39 +08:00
										 |  |  | 			mainTemplate.hooks.assetPath.tap("TemplatedPathPlugin", replacePathVariables); | 
					
						
							| 
									
										
										
										
											2014-08-22 19:51:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-14 04:35:39 +08:00
										 |  |  | 			mainTemplate.hooks.globalHash.tap("TemplatedPathPlugin", (chunk, paths) => { | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 				const outputOptions = mainTemplate.outputOptions; | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | 				const publicPath = outputOptions.publicPath || ""; | 
					
						
							|  |  |  | 				const filename = outputOptions.filename || ""; | 
					
						
							|  |  |  | 				const chunkFilename = outputOptions.chunkFilename || outputOptions.filename; | 
					
						
							|  |  |  | 				if(REGEXP_HASH_FOR_TEST.test(publicPath) || REGEXP_CHUNKHASH_FOR_TEST.test(publicPath) || REGEXP_NAME_FOR_TEST.test(publicPath)) | 
					
						
							|  |  |  | 					return true; | 
					
						
							|  |  |  | 				if(REGEXP_HASH_FOR_TEST.test(filename)) | 
					
						
							|  |  |  | 					return true; | 
					
						
							|  |  |  | 				if(REGEXP_HASH_FOR_TEST.test(chunkFilename)) | 
					
						
							|  |  |  | 					return true; | 
					
						
							|  |  |  | 				if(REGEXP_HASH_FOR_TEST.test(paths.join("|"))) | 
					
						
							|  |  |  | 					return true; | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2015-06-25 05:17:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-14 04:35:39 +08:00
										 |  |  | 			mainTemplate.hooks.hashForChunk.tap("TemplatedPathPlugin", (hash, chunk) => { | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 				const outputOptions = mainTemplate.outputOptions; | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | 				const chunkFilename = outputOptions.chunkFilename || outputOptions.filename; | 
					
						
							|  |  |  | 				if(REGEXP_CHUNKHASH_FOR_TEST.test(chunkFilename)) | 
					
						
							|  |  |  | 					hash.update(JSON.stringify(chunk.getChunkMaps(true, true).hash)); | 
					
						
							|  |  |  | 				if(REGEXP_NAME_FOR_TEST.test(chunkFilename)) | 
					
						
							|  |  |  | 					hash.update(JSON.stringify(chunk.getChunkMaps(true, true).name)); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2015-06-25 05:17:12 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-01-06 23:11:30 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = TemplatedPathPlugin; |