| 
									
										
										
										
											2013-09-13 17:17:57 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2016-12-31 00:34:29 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2013-09-13 17:17:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-31 00:34:29 +08:00
										 |  |  | const ConstDependency = require("./dependencies/ConstDependency"); | 
					
						
							|  |  |  | const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); | 
					
						
							| 
									
										
										
										
											2017-01-09 02:11:26 +08:00
										 |  |  | const ParserHelpers = require("./ParserHelpers"); | 
					
						
							| 
									
										
										
										
											2016-12-31 00:34:29 +08:00
										 |  |  | const NullFactory = require("./NullFactory"); | 
					
						
							| 
									
										
										
										
											2014-06-16 21:18:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | const stringifyObj = obj => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 	return ( | 
					
						
							|  |  |  | 		"Object({" + | 
					
						
							|  |  |  | 		Object.keys(obj) | 
					
						
							|  |  |  | 			.map(key => { | 
					
						
							|  |  |  | 				const code = obj[key]; | 
					
						
							|  |  |  | 				return JSON.stringify(key) + ":" + toCode(code); | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.join(",") + | 
					
						
							|  |  |  | 		"})" | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const toCode = code => { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 	if (code === null) { | 
					
						
							|  |  |  | 		return "null"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (code === undefined) { | 
					
						
							|  |  |  | 		return "undefined"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (code instanceof RegExp && code.toString) { | 
					
						
							|  |  |  | 		return code.toString(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (typeof code === "function" && code.toString) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		return "(" + code.toString() + ")"; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (typeof code === "object") { | 
					
						
							|  |  |  | 		return stringifyObj(code); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return code + ""; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-31 00:34:29 +08:00
										 |  |  | class DefinePlugin { | 
					
						
							|  |  |  | 	constructor(definitions) { | 
					
						
							|  |  |  | 		this.definitions = definitions; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-31 00:34:29 +08:00
										 |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											2017-02-05 07:22:33 +08:00
										 |  |  | 		const definitions = this.definitions; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		compiler.hooks.compilation.tap( | 
					
						
							|  |  |  | 			"DefinePlugin", | 
					
						
							|  |  |  | 			(compilation, { normalModuleFactory }) => { | 
					
						
							|  |  |  | 				compilation.dependencyFactories.set(ConstDependency, new NullFactory()); | 
					
						
							|  |  |  | 				compilation.dependencyTemplates.set( | 
					
						
							|  |  |  | 					ConstDependency, | 
					
						
							|  |  |  | 					new ConstDependency.Template() | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				const handler = parser => { | 
					
						
							|  |  |  | 					const walkDefinitions = (definitions, prefix) => { | 
					
						
							|  |  |  | 						Object.keys(definitions).forEach(key => { | 
					
						
							|  |  |  | 							const code = definitions[key]; | 
					
						
							|  |  |  | 							if ( | 
					
						
							|  |  |  | 								code && | 
					
						
							|  |  |  | 								typeof code === "object" && | 
					
						
							|  |  |  | 								!(code instanceof RegExp) | 
					
						
							|  |  |  | 							) { | 
					
						
							|  |  |  | 								walkDefinitions(code, prefix + key + "."); | 
					
						
							|  |  |  | 								applyObjectDefine(prefix + key, code); | 
					
						
							|  |  |  | 								return; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							applyDefineKey(prefix, key); | 
					
						
							|  |  |  | 							applyDefine(prefix + key, code); | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 					}; | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					const applyDefineKey = (prefix, key) => { | 
					
						
							|  |  |  | 						const splittedKey = key.split("."); | 
					
						
							|  |  |  | 						splittedKey.slice(1).forEach((_, i) => { | 
					
						
							|  |  |  | 							const fullKey = prefix + splittedKey.slice(0, i + 1).join("."); | 
					
						
							|  |  |  | 							parser.hooks.canRename | 
					
						
							|  |  |  | 								.for(fullKey) | 
					
						
							|  |  |  | 								.tap("DefinePlugin", ParserHelpers.approve); | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 					}; | 
					
						
							| 
									
										
										
										
											2016-12-31 00:34:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					const applyDefine = (key, code) => { | 
					
						
							|  |  |  | 						const isTypeof = /^typeof\s+/.test(key); | 
					
						
							|  |  |  | 						if (isTypeof) key = key.replace(/^typeof\s+/, ""); | 
					
						
							|  |  |  | 						let recurse = false; | 
					
						
							|  |  |  | 						let recurseTypeof = false; | 
					
						
							|  |  |  | 						code = toCode(code); | 
					
						
							|  |  |  | 						if (!isTypeof) { | 
					
						
							|  |  |  | 							parser.hooks.canRename | 
					
						
							|  |  |  | 								.for(key) | 
					
						
							|  |  |  | 								.tap("DefinePlugin", ParserHelpers.approve); | 
					
						
							|  |  |  | 							parser.hooks.evaluateIdentifier | 
					
						
							|  |  |  | 								.for(key) | 
					
						
							|  |  |  | 								.tap("DefinePlugin", expr => { | 
					
						
							|  |  |  | 									/** | 
					
						
							|  |  |  | 									 * this is needed in case there is a recursion in the DefinePlugin | 
					
						
							|  |  |  | 									 * to prevent an endless recursion | 
					
						
							|  |  |  | 									 * e.g.: new DefinePlugin({ | 
					
						
							|  |  |  | 									 * "a": "b", | 
					
						
							|  |  |  | 									 * "b": "a" | 
					
						
							|  |  |  | 									 * }); | 
					
						
							|  |  |  | 									 */ | 
					
						
							|  |  |  | 									if (recurse) return; | 
					
						
							|  |  |  | 									recurse = true; | 
					
						
							|  |  |  | 									const res = parser.evaluate(code); | 
					
						
							|  |  |  | 									recurse = false; | 
					
						
							|  |  |  | 									res.setRange(expr.range); | 
					
						
							|  |  |  | 									return res; | 
					
						
							|  |  |  | 								}); | 
					
						
							|  |  |  | 							parser.hooks.expression | 
					
						
							|  |  |  | 								.for(key) | 
					
						
							|  |  |  | 								.tap( | 
					
						
							|  |  |  | 									"DefinePlugin", | 
					
						
							|  |  |  | 									/__webpack_require__/.test(code) | 
					
						
							|  |  |  | 										? ParserHelpers.toConstantDependencyWithWebpackRequire( | 
					
						
							|  |  |  | 												parser, | 
					
						
							|  |  |  | 												code | 
					
						
							| 
									
										
										
										
											2018-03-26 22:56:10 +08:00
										 |  |  | 										  ) | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 										: ParserHelpers.toConstantDependency(parser, code) | 
					
						
							|  |  |  | 								); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						const typeofCode = isTypeof ? code : "typeof (" + code + ")"; | 
					
						
							|  |  |  | 						parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", expr => { | 
					
						
							| 
									
										
										
										
											2017-02-06 19:51:26 +08:00
										 |  |  | 							/** | 
					
						
							|  |  |  | 							 * this is needed in case there is a recursion in the DefinePlugin | 
					
						
							|  |  |  | 							 * to prevent an endless recursion | 
					
						
							|  |  |  | 							 * e.g.: new DefinePlugin({ | 
					
						
							| 
									
										
										
										
											2018-02-26 10:49:41 +08:00
										 |  |  | 							 * "typeof a": "typeof b", | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							 * "typeof b": "typeof a" | 
					
						
							| 
									
										
										
										
											2017-02-06 19:51:26 +08:00
										 |  |  | 							 * }); | 
					
						
							|  |  |  | 							 */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							if (recurseTypeof) return; | 
					
						
							|  |  |  | 							recurseTypeof = true; | 
					
						
							|  |  |  | 							const res = parser.evaluate(typeofCode); | 
					
						
							|  |  |  | 							recurseTypeof = false; | 
					
						
							| 
									
										
										
										
											2016-12-31 00:34:29 +08:00
										 |  |  | 							res.setRange(expr.range); | 
					
						
							|  |  |  | 							return res; | 
					
						
							|  |  |  | 						}); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						parser.hooks.typeof.for(key).tap("DefinePlugin", expr => { | 
					
						
							|  |  |  | 							const res = parser.evaluate(typeofCode); | 
					
						
							|  |  |  | 							if (!res.isString()) return; | 
					
						
							|  |  |  | 							return ParserHelpers.toConstantDependency( | 
					
						
							|  |  |  | 								parser, | 
					
						
							|  |  |  | 								JSON.stringify(res.string) | 
					
						
							|  |  |  | 							).bind(parser)(expr); | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 					}; | 
					
						
							| 
									
										
										
										
											2016-09-14 18:04:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					const applyObjectDefine = (key, obj) => { | 
					
						
							|  |  |  | 						const code = stringifyObj(obj); | 
					
						
							|  |  |  | 						parser.hooks.canRename | 
					
						
							|  |  |  | 							.for(key) | 
					
						
							|  |  |  | 							.tap("DefinePlugin", ParserHelpers.approve); | 
					
						
							|  |  |  | 						parser.hooks.evaluateIdentifier | 
					
						
							|  |  |  | 							.for(key) | 
					
						
							|  |  |  | 							.tap("DefinePlugin", expr => | 
					
						
							|  |  |  | 								new BasicEvaluatedExpression().setTruthy().setRange(expr.range) | 
					
						
							|  |  |  | 							); | 
					
						
							|  |  |  | 						parser.hooks.evaluateTypeof | 
					
						
							|  |  |  | 							.for(key) | 
					
						
							|  |  |  | 							.tap("DefinePlugin", ParserHelpers.evaluateToString("object")); | 
					
						
							|  |  |  | 						parser.hooks.expression | 
					
						
							|  |  |  | 							.for(key) | 
					
						
							|  |  |  | 							.tap( | 
					
						
							|  |  |  | 								"DefinePlugin", | 
					
						
							|  |  |  | 								/__webpack_require__/.test(code) | 
					
						
							|  |  |  | 									? ParserHelpers.toConstantDependencyWithWebpackRequire( | 
					
						
							|  |  |  | 											parser, | 
					
						
							|  |  |  | 											code | 
					
						
							| 
									
										
										
										
											2018-03-26 22:56:10 +08:00
										 |  |  | 									  ) | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 									: ParserHelpers.toConstantDependency(parser, code) | 
					
						
							|  |  |  | 							); | 
					
						
							|  |  |  | 						parser.hooks.typeof | 
					
						
							|  |  |  | 							.for(key) | 
					
						
							|  |  |  | 							.tap( | 
					
						
							|  |  |  | 								"DefinePlugin", | 
					
						
							|  |  |  | 								ParserHelpers.toConstantDependency( | 
					
						
							|  |  |  | 									parser, | 
					
						
							|  |  |  | 									JSON.stringify("object") | 
					
						
							|  |  |  | 								) | 
					
						
							|  |  |  | 							); | 
					
						
							|  |  |  | 					}; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					walkDefinitions(definitions, ""); | 
					
						
							|  |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2017-12-14 17:22:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				normalModuleFactory.hooks.parser | 
					
						
							|  |  |  | 					.for("javascript/auto") | 
					
						
							|  |  |  | 					.tap("DefinePlugin", handler); | 
					
						
							|  |  |  | 				normalModuleFactory.hooks.parser | 
					
						
							|  |  |  | 					.for("javascript/dynamic") | 
					
						
							|  |  |  | 					.tap("DefinePlugin", handler); | 
					
						
							|  |  |  | 				normalModuleFactory.hooks.parser | 
					
						
							|  |  |  | 					.for("javascript/esm") | 
					
						
							|  |  |  | 					.tap("DefinePlugin", handler); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2016-12-31 00:34:29 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports = DefinePlugin; |