You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			668 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			668 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | /* | ||
|  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | ||
|  | 	Author Tobias Koppers @sokra | ||
|  | */ | ||
|  | 
 | ||
|  | "use strict"; | ||
|  | 
 | ||
|  | const { | ||
|  | 	JAVASCRIPT_MODULE_TYPE_AUTO, | ||
|  | 	JAVASCRIPT_MODULE_TYPE_ESM, | ||
|  | 	JAVASCRIPT_MODULE_TYPE_DYNAMIC | ||
|  | } = require("./ModuleTypeConstants"); | ||
|  | const RuntimeGlobals = require("./RuntimeGlobals"); | ||
|  | const WebpackError = require("./WebpackError"); | ||
|  | const ConstDependency = require("./dependencies/ConstDependency"); | ||
|  | const BasicEvaluatedExpression = require("./javascript/BasicEvaluatedExpression"); | ||
|  | 
 | ||
|  | const { | ||
|  | 	evaluateToString, | ||
|  | 	toConstantDependency | ||
|  | } = require("./javascript/JavascriptParserHelpers"); | ||
|  | const createHash = require("./util/createHash"); | ||
|  | 
 | ||
|  | /** @typedef {import("estree").Expression} Expression */ | ||
|  | /** @typedef {import("./Compiler")} Compiler */ | ||
|  | /** @typedef {import("./NormalModule")} NormalModule */ | ||
|  | /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ | ||
|  | /** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */ | ||
|  | /** @typedef {import("./logging/Logger").Logger} Logger */ | ||
|  | 
 | ||
|  | /** @typedef {null|undefined|RegExp|Function|string|number|boolean|bigint|undefined} CodeValuePrimitive */ | ||
|  | /** @typedef {RecursiveArrayOrRecord<CodeValuePrimitive|RuntimeValue>} CodeValue */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * @typedef {Object} RuntimeValueOptions | ||
|  |  * @property {string[]=} fileDependencies | ||
|  |  * @property {string[]=} contextDependencies | ||
|  |  * @property {string[]=} missingDependencies | ||
|  |  * @property {string[]=} buildDependencies | ||
|  |  * @property {string|function(): string=} version | ||
|  |  */ | ||
|  | 
 | ||
|  | class RuntimeValue { | ||
|  | 	/** | ||
|  | 	 * @param {function({ module: NormalModule, key: string, readonly version: string | undefined }): CodeValuePrimitive} fn generator function | ||
|  | 	 * @param {true | string[] | RuntimeValueOptions=} options options | ||
|  | 	 */ | ||
|  | 	constructor(fn, options) { | ||
|  | 		this.fn = fn; | ||
|  | 		if (Array.isArray(options)) { | ||
|  | 			options = { | ||
|  | 				fileDependencies: options | ||
|  | 			}; | ||
|  | 		} | ||
|  | 		this.options = options || {}; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	get fileDependencies() { | ||
|  | 		return this.options === true ? true : this.options.fileDependencies; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {JavascriptParser} parser the parser | ||
|  | 	 * @param {Map<string, string | Set<string>>} valueCacheVersions valueCacheVersions | ||
|  | 	 * @param {string} key the defined key | ||
|  | 	 * @returns {CodeValuePrimitive} code | ||
|  | 	 */ | ||
|  | 	exec(parser, valueCacheVersions, key) { | ||
|  | 		const buildInfo = parser.state.module.buildInfo; | ||
|  | 		if (this.options === true) { | ||
|  | 			buildInfo.cacheable = false; | ||
|  | 		} else { | ||
|  | 			if (this.options.fileDependencies) { | ||
|  | 				for (const dep of this.options.fileDependencies) { | ||
|  | 					buildInfo.fileDependencies.add(dep); | ||
|  | 				} | ||
|  | 			} | ||
|  | 			if (this.options.contextDependencies) { | ||
|  | 				for (const dep of this.options.contextDependencies) { | ||
|  | 					buildInfo.contextDependencies.add(dep); | ||
|  | 				} | ||
|  | 			} | ||
|  | 			if (this.options.missingDependencies) { | ||
|  | 				for (const dep of this.options.missingDependencies) { | ||
|  | 					buildInfo.missingDependencies.add(dep); | ||
|  | 				} | ||
|  | 			} | ||
|  | 			if (this.options.buildDependencies) { | ||
|  | 				for (const dep of this.options.buildDependencies) { | ||
|  | 					buildInfo.buildDependencies.add(dep); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return this.fn({ | ||
|  | 			module: parser.state.module, | ||
|  | 			key, | ||
|  | 			get version() { | ||
|  | 				return /** @type {string} */ ( | ||
|  | 					valueCacheVersions.get(VALUE_DEP_PREFIX + key) | ||
|  | 				); | ||
|  | 			} | ||
|  | 		}); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	getCacheVersion() { | ||
|  | 		return this.options === true | ||
|  | 			? undefined | ||
|  | 			: (typeof this.options.version === "function" | ||
|  | 					? this.options.version() | ||
|  | 					: this.options.version) || "unset"; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * @param {any[]|{[k: string]: any}} obj obj | ||
|  |  * @param {JavascriptParser} parser Parser | ||
|  |  * @param {Map<string, string | Set<string>>} valueCacheVersions valueCacheVersions | ||
|  |  * @param {string} key the defined key | ||
|  |  * @param {RuntimeTemplate} runtimeTemplate the runtime template | ||
|  |  * @param {Logger} logger the logger object | ||
|  |  * @param {boolean|undefined|null=} asiSafe asi safe (undefined: unknown, null: unneeded) | ||
|  |  * @param {Set<string>|undefined=} objKeys used keys | ||
|  |  * @returns {string} code converted to string that evaluates | ||
|  |  */ | ||
|  | const stringifyObj = ( | ||
|  | 	obj, | ||
|  | 	parser, | ||
|  | 	valueCacheVersions, | ||
|  | 	key, | ||
|  | 	runtimeTemplate, | ||
|  | 	logger, | ||
|  | 	asiSafe, | ||
|  | 	objKeys | ||
|  | ) => { | ||
|  | 	let code; | ||
|  | 	let arr = Array.isArray(obj); | ||
|  | 	if (arr) { | ||
|  | 		code = `[${obj | ||
|  | 			.map(code => | ||
|  | 				toCode( | ||
|  | 					code, | ||
|  | 					parser, | ||
|  | 					valueCacheVersions, | ||
|  | 					key, | ||
|  | 					runtimeTemplate, | ||
|  | 					logger, | ||
|  | 					null | ||
|  | 				) | ||
|  | 			) | ||
|  | 			.join(",")}]`;
 | ||
|  | 	} else { | ||
|  | 		let keys = Object.keys(obj); | ||
|  | 		if (objKeys) { | ||
|  | 			if (objKeys.size === 0) keys = []; | ||
|  | 			else keys = keys.filter(k => objKeys.has(k)); | ||
|  | 		} | ||
|  | 		code = `{${keys | ||
|  | 			.map(key => { | ||
|  | 				const code = obj[key]; | ||
|  | 				return ( | ||
|  | 					JSON.stringify(key) + | ||
|  | 					":" + | ||
|  | 					toCode( | ||
|  | 						code, | ||
|  | 						parser, | ||
|  | 						valueCacheVersions, | ||
|  | 						key, | ||
|  | 						runtimeTemplate, | ||
|  | 						logger, | ||
|  | 						null | ||
|  | 					) | ||
|  | 				); | ||
|  | 			}) | ||
|  | 			.join(",")}}`;
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	switch (asiSafe) { | ||
|  | 		case null: | ||
|  | 			return code; | ||
|  | 		case true: | ||
|  | 			return arr ? code : `(${code})`; | ||
|  | 		case false: | ||
|  | 			return arr ? `;${code}` : `;(${code})`; | ||
|  | 		default: | ||
|  | 			return `/*#__PURE__*/Object(${code})`; | ||
|  | 	} | ||
|  | }; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Convert code to a string that evaluates | ||
|  |  * @param {CodeValue} code Code to evaluate | ||
|  |  * @param {JavascriptParser} parser Parser | ||
|  |  * @param {Map<string, string | Set<string>>} valueCacheVersions valueCacheVersions | ||
|  |  * @param {string} key the defined key | ||
|  |  * @param {RuntimeTemplate} runtimeTemplate the runtime template | ||
|  |  * @param {Logger} logger the logger object | ||
|  |  * @param {boolean|undefined|null=} asiSafe asi safe (undefined: unknown, null: unneeded) | ||
|  |  * @param {Set<string>|undefined=} objKeys used keys | ||
|  |  * @returns {string} code converted to string that evaluates | ||
|  |  */ | ||
|  | const toCode = ( | ||
|  | 	code, | ||
|  | 	parser, | ||
|  | 	valueCacheVersions, | ||
|  | 	key, | ||
|  | 	runtimeTemplate, | ||
|  | 	logger, | ||
|  | 	asiSafe, | ||
|  | 	objKeys | ||
|  | ) => { | ||
|  | 	const transformToCode = () => { | ||
|  | 		if (code === null) { | ||
|  | 			return "null"; | ||
|  | 		} | ||
|  | 		if (code === undefined) { | ||
|  | 			return "undefined"; | ||
|  | 		} | ||
|  | 		if (Object.is(code, -0)) { | ||
|  | 			return "-0"; | ||
|  | 		} | ||
|  | 		if (code instanceof RuntimeValue) { | ||
|  | 			return toCode( | ||
|  | 				code.exec(parser, valueCacheVersions, key), | ||
|  | 				parser, | ||
|  | 				valueCacheVersions, | ||
|  | 				key, | ||
|  | 				runtimeTemplate, | ||
|  | 				logger, | ||
|  | 				asiSafe | ||
|  | 			); | ||
|  | 		} | ||
|  | 		if (code instanceof RegExp && code.toString) { | ||
|  | 			return code.toString(); | ||
|  | 		} | ||
|  | 		if (typeof code === "function" && code.toString) { | ||
|  | 			return "(" + code.toString() + ")"; | ||
|  | 		} | ||
|  | 		if (typeof code === "object") { | ||
|  | 			return stringifyObj( | ||
|  | 				code, | ||
|  | 				parser, | ||
|  | 				valueCacheVersions, | ||
|  | 				key, | ||
|  | 				runtimeTemplate, | ||
|  | 				logger, | ||
|  | 				asiSafe, | ||
|  | 				objKeys | ||
|  | 			); | ||
|  | 		} | ||
|  | 		if (typeof code === "bigint") { | ||
|  | 			return runtimeTemplate.supportsBigIntLiteral() | ||
|  | 				? `${code}n` | ||
|  | 				: `BigInt("${code}")`; | ||
|  | 		} | ||
|  | 		return code + ""; | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	const strCode = transformToCode(); | ||
|  | 
 | ||
|  | 	logger.log(`Replaced "${key}" with "${strCode}"`); | ||
|  | 
 | ||
|  | 	return strCode; | ||
|  | }; | ||
|  | 
 | ||
|  | const toCacheVersion = code => { | ||
|  | 	if (code === null) { | ||
|  | 		return "null"; | ||
|  | 	} | ||
|  | 	if (code === undefined) { | ||
|  | 		return "undefined"; | ||
|  | 	} | ||
|  | 	if (Object.is(code, -0)) { | ||
|  | 		return "-0"; | ||
|  | 	} | ||
|  | 	if (code instanceof RuntimeValue) { | ||
|  | 		return code.getCacheVersion(); | ||
|  | 	} | ||
|  | 	if (code instanceof RegExp && code.toString) { | ||
|  | 		return code.toString(); | ||
|  | 	} | ||
|  | 	if (typeof code === "function" && code.toString) { | ||
|  | 		return "(" + code.toString() + ")"; | ||
|  | 	} | ||
|  | 	if (typeof code === "object") { | ||
|  | 		const items = Object.keys(code).map(key => ({ | ||
|  | 			key, | ||
|  | 			value: toCacheVersion(code[key]) | ||
|  | 		})); | ||
|  | 		if (items.some(({ value }) => value === undefined)) return undefined; | ||
|  | 		return `{${items.map(({ key, value }) => `${key}: ${value}`).join(", ")}}`; | ||
|  | 	} | ||
|  | 	if (typeof code === "bigint") { | ||
|  | 		return `${code}n`; | ||
|  | 	} | ||
|  | 	return code + ""; | ||
|  | }; | ||
|  | 
 | ||
|  | const PLUGIN_NAME = "DefinePlugin"; | ||
|  | const VALUE_DEP_PREFIX = `webpack/${PLUGIN_NAME} `; | ||
|  | const VALUE_DEP_MAIN = `webpack/${PLUGIN_NAME}_hash`; | ||
|  | const TYPEOF_OPERATOR_REGEXP = /^typeof\s+/; | ||
|  | const WEBPACK_REQUIRE_FUNCTION_REGEXP = /__webpack_require__\s*(!?\.)/; | ||
|  | const WEBPACK_REQUIRE_IDENTIFIER_REGEXP = /__webpack_require__/; | ||
|  | 
 | ||
|  | class DefinePlugin { | ||
|  | 	/** | ||
|  | 	 * Create a new define plugin | ||
|  | 	 * @param {Record<string, CodeValue>} definitions A map of global object definitions | ||
|  | 	 */ | ||
|  | 	constructor(definitions) { | ||
|  | 		this.definitions = definitions; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {function({ module: NormalModule, key: string, readonly version: string | undefined }): CodeValuePrimitive} fn generator function | ||
|  | 	 * @param {true | string[] | RuntimeValueOptions=} options options | ||
|  | 	 * @returns {RuntimeValue} runtime value | ||
|  | 	 */ | ||
|  | 	static runtimeValue(fn, options) { | ||
|  | 		return new RuntimeValue(fn, options); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * Apply the plugin | ||
|  | 	 * @param {Compiler} compiler the compiler instance | ||
|  | 	 * @returns {void} | ||
|  | 	 */ | ||
|  | 	apply(compiler) { | ||
|  | 		const definitions = this.definitions; | ||
|  | 		compiler.hooks.compilation.tap( | ||
|  | 			PLUGIN_NAME, | ||
|  | 			(compilation, { normalModuleFactory }) => { | ||
|  | 				const logger = compilation.getLogger("webpack.DefinePlugin"); | ||
|  | 				compilation.dependencyTemplates.set( | ||
|  | 					ConstDependency, | ||
|  | 					new ConstDependency.Template() | ||
|  | 				); | ||
|  | 				const { runtimeTemplate } = compilation; | ||
|  | 
 | ||
|  | 				const mainHash = createHash(compilation.outputOptions.hashFunction); | ||
|  | 				mainHash.update( | ||
|  | 					/** @type {string} */ ( | ||
|  | 						compilation.valueCacheVersions.get(VALUE_DEP_MAIN) | ||
|  | 					) || "" | ||
|  | 				); | ||
|  | 
 | ||
|  | 				/** | ||
|  | 				 * Handler | ||
|  | 				 * @param {JavascriptParser} parser Parser | ||
|  | 				 * @returns {void} | ||
|  | 				 */ | ||
|  | 				const handler = parser => { | ||
|  | 					const mainValue = compilation.valueCacheVersions.get(VALUE_DEP_MAIN); | ||
|  | 					parser.hooks.program.tap(PLUGIN_NAME, () => { | ||
|  | 						const { buildInfo } = parser.state.module; | ||
|  | 						if (!buildInfo.valueDependencies) | ||
|  | 							buildInfo.valueDependencies = new Map(); | ||
|  | 						buildInfo.valueDependencies.set(VALUE_DEP_MAIN, mainValue); | ||
|  | 					}); | ||
|  | 
 | ||
|  | 					const addValueDependency = key => { | ||
|  | 						const { buildInfo } = parser.state.module; | ||
|  | 						buildInfo.valueDependencies.set( | ||
|  | 							VALUE_DEP_PREFIX + key, | ||
|  | 							compilation.valueCacheVersions.get(VALUE_DEP_PREFIX + key) | ||
|  | 						); | ||
|  | 					}; | ||
|  | 
 | ||
|  | 					const withValueDependency = | ||
|  | 						(key, fn) => | ||
|  | 						(...args) => { | ||
|  | 							addValueDependency(key); | ||
|  | 							return fn(...args); | ||
|  | 						}; | ||
|  | 
 | ||
|  | 					/** | ||
|  | 					 * Walk definitions | ||
|  | 					 * @param {Object} definitions Definitions map | ||
|  | 					 * @param {string} prefix Prefix string | ||
|  | 					 * @returns {void} | ||
|  | 					 */ | ||
|  | 					const walkDefinitions = (definitions, prefix) => { | ||
|  | 						Object.keys(definitions).forEach(key => { | ||
|  | 							const code = definitions[key]; | ||
|  | 							if ( | ||
|  | 								code && | ||
|  | 								typeof code === "object" && | ||
|  | 								!(code instanceof RuntimeValue) && | ||
|  | 								!(code instanceof RegExp) | ||
|  | 							) { | ||
|  | 								walkDefinitions(code, prefix + key + "."); | ||
|  | 								applyObjectDefine(prefix + key, code); | ||
|  | 								return; | ||
|  | 							} | ||
|  | 							applyDefineKey(prefix, key); | ||
|  | 							applyDefine(prefix + key, code); | ||
|  | 						}); | ||
|  | 					}; | ||
|  | 
 | ||
|  | 					/** | ||
|  | 					 * Apply define key | ||
|  | 					 * @param {string} prefix Prefix | ||
|  | 					 * @param {string} key Key | ||
|  | 					 * @returns {void} | ||
|  | 					 */ | ||
|  | 					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(PLUGIN_NAME, () => { | ||
|  | 								addValueDependency(key); | ||
|  | 								return true; | ||
|  | 							}); | ||
|  | 						}); | ||
|  | 					}; | ||
|  | 
 | ||
|  | 					/** | ||
|  | 					 * Apply Code | ||
|  | 					 * @param {string} key Key | ||
|  | 					 * @param {CodeValue} code Code | ||
|  | 					 * @returns {void} | ||
|  | 					 */ | ||
|  | 					const applyDefine = (key, code) => { | ||
|  | 						const originalKey = key; | ||
|  | 						const isTypeof = TYPEOF_OPERATOR_REGEXP.test(key); | ||
|  | 						if (isTypeof) key = key.replace(TYPEOF_OPERATOR_REGEXP, ""); | ||
|  | 						let recurse = false; | ||
|  | 						let recurseTypeof = false; | ||
|  | 						if (!isTypeof) { | ||
|  | 							parser.hooks.canRename.for(key).tap(PLUGIN_NAME, () => { | ||
|  | 								addValueDependency(originalKey); | ||
|  | 								return true; | ||
|  | 							}); | ||
|  | 							parser.hooks.evaluateIdentifier | ||
|  | 								.for(key) | ||
|  | 								.tap(PLUGIN_NAME, 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; | ||
|  | 									addValueDependency(originalKey); | ||
|  | 									recurse = true; | ||
|  | 									const res = parser.evaluate( | ||
|  | 										toCode( | ||
|  | 											code, | ||
|  | 											parser, | ||
|  | 											compilation.valueCacheVersions, | ||
|  | 											key, | ||
|  | 											runtimeTemplate, | ||
|  | 											logger, | ||
|  | 											null | ||
|  | 										) | ||
|  | 									); | ||
|  | 									recurse = false; | ||
|  | 									res.setRange(expr.range); | ||
|  | 									return res; | ||
|  | 								}); | ||
|  | 							parser.hooks.expression.for(key).tap(PLUGIN_NAME, expr => { | ||
|  | 								addValueDependency(originalKey); | ||
|  | 								let strCode = toCode( | ||
|  | 									code, | ||
|  | 									parser, | ||
|  | 									compilation.valueCacheVersions, | ||
|  | 									originalKey, | ||
|  | 									runtimeTemplate, | ||
|  | 									logger, | ||
|  | 									!parser.isAsiPosition(expr.range[0]), | ||
|  | 									parser.destructuringAssignmentPropertiesFor(expr) | ||
|  | 								); | ||
|  | 
 | ||
|  | 								if (parser.scope.inShorthand) { | ||
|  | 									strCode = parser.scope.inShorthand + ":" + strCode; | ||
|  | 								} | ||
|  | 
 | ||
|  | 								if (WEBPACK_REQUIRE_FUNCTION_REGEXP.test(strCode)) { | ||
|  | 									return toConstantDependency(parser, strCode, [ | ||
|  | 										RuntimeGlobals.require | ||
|  | 									])(expr); | ||
|  | 								} else if (WEBPACK_REQUIRE_IDENTIFIER_REGEXP.test(strCode)) { | ||
|  | 									return toConstantDependency(parser, strCode, [ | ||
|  | 										RuntimeGlobals.requireScope | ||
|  | 									])(expr); | ||
|  | 								} else { | ||
|  | 									return toConstantDependency(parser, strCode)(expr); | ||
|  | 								} | ||
|  | 							}); | ||
|  | 						} | ||
|  | 						parser.hooks.evaluateTypeof.for(key).tap(PLUGIN_NAME, expr => { | ||
|  | 							/** | ||
|  | 							 * this is needed in case there is a recursion in the DefinePlugin | ||
|  | 							 * to prevent an endless recursion | ||
|  | 							 * e.g.: new DefinePlugin({ | ||
|  | 							 * "typeof a": "typeof b", | ||
|  | 							 * "typeof b": "typeof a" | ||
|  | 							 * }); | ||
|  | 							 */ | ||
|  | 							if (recurseTypeof) return; | ||
|  | 							recurseTypeof = true; | ||
|  | 							addValueDependency(originalKey); | ||
|  | 							const codeCode = toCode( | ||
|  | 								code, | ||
|  | 								parser, | ||
|  | 								compilation.valueCacheVersions, | ||
|  | 								originalKey, | ||
|  | 								runtimeTemplate, | ||
|  | 								logger, | ||
|  | 								null | ||
|  | 							); | ||
|  | 							const typeofCode = isTypeof | ||
|  | 								? codeCode | ||
|  | 								: "typeof (" + codeCode + ")"; | ||
|  | 							const res = parser.evaluate(typeofCode); | ||
|  | 							recurseTypeof = false; | ||
|  | 							res.setRange(expr.range); | ||
|  | 							return res; | ||
|  | 						}); | ||
|  | 						parser.hooks.typeof.for(key).tap(PLUGIN_NAME, expr => { | ||
|  | 							addValueDependency(originalKey); | ||
|  | 							const codeCode = toCode( | ||
|  | 								code, | ||
|  | 								parser, | ||
|  | 								compilation.valueCacheVersions, | ||
|  | 								originalKey, | ||
|  | 								runtimeTemplate, | ||
|  | 								logger, | ||
|  | 								null | ||
|  | 							); | ||
|  | 							const typeofCode = isTypeof | ||
|  | 								? codeCode | ||
|  | 								: "typeof (" + codeCode + ")"; | ||
|  | 							const res = parser.evaluate(typeofCode); | ||
|  | 							if (!res.isString()) return; | ||
|  | 							return toConstantDependency( | ||
|  | 								parser, | ||
|  | 								JSON.stringify(res.string) | ||
|  | 							).bind(parser)(expr); | ||
|  | 						}); | ||
|  | 					}; | ||
|  | 
 | ||
|  | 					/** | ||
|  | 					 * Apply Object | ||
|  | 					 * @param {string} key Key | ||
|  | 					 * @param {Object} obj Object | ||
|  | 					 * @returns {void} | ||
|  | 					 */ | ||
|  | 					const applyObjectDefine = (key, obj) => { | ||
|  | 						parser.hooks.canRename.for(key).tap(PLUGIN_NAME, () => { | ||
|  | 							addValueDependency(key); | ||
|  | 							return true; | ||
|  | 						}); | ||
|  | 						parser.hooks.evaluateIdentifier.for(key).tap(PLUGIN_NAME, expr => { | ||
|  | 							addValueDependency(key); | ||
|  | 							return new BasicEvaluatedExpression() | ||
|  | 								.setTruthy() | ||
|  | 								.setSideEffects(false) | ||
|  | 								.setRange(expr.range); | ||
|  | 						}); | ||
|  | 						parser.hooks.evaluateTypeof | ||
|  | 							.for(key) | ||
|  | 							.tap( | ||
|  | 								PLUGIN_NAME, | ||
|  | 								withValueDependency(key, evaluateToString("object")) | ||
|  | 							); | ||
|  | 						parser.hooks.expression.for(key).tap(PLUGIN_NAME, expr => { | ||
|  | 							addValueDependency(key); | ||
|  | 							let strCode = stringifyObj( | ||
|  | 								obj, | ||
|  | 								parser, | ||
|  | 								compilation.valueCacheVersions, | ||
|  | 								key, | ||
|  | 								runtimeTemplate, | ||
|  | 								logger, | ||
|  | 								!parser.isAsiPosition(expr.range[0]), | ||
|  | 								parser.destructuringAssignmentPropertiesFor(expr) | ||
|  | 							); | ||
|  | 
 | ||
|  | 							if (parser.scope.inShorthand) { | ||
|  | 								strCode = parser.scope.inShorthand + ":" + strCode; | ||
|  | 							} | ||
|  | 
 | ||
|  | 							if (WEBPACK_REQUIRE_FUNCTION_REGEXP.test(strCode)) { | ||
|  | 								return toConstantDependency(parser, strCode, [ | ||
|  | 									RuntimeGlobals.require | ||
|  | 								])(expr); | ||
|  | 							} else if (WEBPACK_REQUIRE_IDENTIFIER_REGEXP.test(strCode)) { | ||
|  | 								return toConstantDependency(parser, strCode, [ | ||
|  | 									RuntimeGlobals.requireScope | ||
|  | 								])(expr); | ||
|  | 							} else { | ||
|  | 								return toConstantDependency(parser, strCode)(expr); | ||
|  | 							} | ||
|  | 						}); | ||
|  | 						parser.hooks.typeof | ||
|  | 							.for(key) | ||
|  | 							.tap( | ||
|  | 								PLUGIN_NAME, | ||
|  | 								withValueDependency( | ||
|  | 									key, | ||
|  | 									toConstantDependency(parser, JSON.stringify("object")) | ||
|  | 								) | ||
|  | 							); | ||
|  | 					}; | ||
|  | 
 | ||
|  | 					walkDefinitions(definitions, ""); | ||
|  | 				}; | ||
|  | 
 | ||
|  | 				normalModuleFactory.hooks.parser | ||
|  | 					.for(JAVASCRIPT_MODULE_TYPE_AUTO) | ||
|  | 					.tap(PLUGIN_NAME, handler); | ||
|  | 				normalModuleFactory.hooks.parser | ||
|  | 					.for(JAVASCRIPT_MODULE_TYPE_DYNAMIC) | ||
|  | 					.tap(PLUGIN_NAME, handler); | ||
|  | 				normalModuleFactory.hooks.parser | ||
|  | 					.for(JAVASCRIPT_MODULE_TYPE_ESM) | ||
|  | 					.tap(PLUGIN_NAME, handler); | ||
|  | 
 | ||
|  | 				/** | ||
|  | 				 * Walk definitions | ||
|  | 				 * @param {Object} definitions Definitions map | ||
|  | 				 * @param {string} prefix Prefix string | ||
|  | 				 * @returns {void} | ||
|  | 				 */ | ||
|  | 				const walkDefinitionsForValues = (definitions, prefix) => { | ||
|  | 					Object.keys(definitions).forEach(key => { | ||
|  | 						const code = definitions[key]; | ||
|  | 						const version = toCacheVersion(code); | ||
|  | 						const name = VALUE_DEP_PREFIX + prefix + key; | ||
|  | 						mainHash.update("|" + prefix + key); | ||
|  | 						const oldVersion = compilation.valueCacheVersions.get(name); | ||
|  | 						if (oldVersion === undefined) { | ||
|  | 							compilation.valueCacheVersions.set(name, version); | ||
|  | 						} else if (oldVersion !== version) { | ||
|  | 							const warning = new WebpackError( | ||
|  | 								`${PLUGIN_NAME}\nConflicting values for '${prefix + key}'` | ||
|  | 							); | ||
|  | 							warning.details = `'${oldVersion}' !== '${version}'`; | ||
|  | 							warning.hideStack = true; | ||
|  | 							compilation.warnings.push(warning); | ||
|  | 						} | ||
|  | 						if ( | ||
|  | 							code && | ||
|  | 							typeof code === "object" && | ||
|  | 							!(code instanceof RuntimeValue) && | ||
|  | 							!(code instanceof RegExp) | ||
|  | 						) { | ||
|  | 							walkDefinitionsForValues(code, prefix + key + "."); | ||
|  | 						} | ||
|  | 					}); | ||
|  | 				}; | ||
|  | 
 | ||
|  | 				walkDefinitionsForValues(definitions, ""); | ||
|  | 
 | ||
|  | 				compilation.valueCacheVersions.set( | ||
|  | 					VALUE_DEP_MAIN, | ||
|  | 					/** @type {string} */ (mainHash.digest("hex").slice(0, 8)) | ||
|  | 				); | ||
|  | 			} | ||
|  | 		); | ||
|  | 	} | ||
|  | } | ||
|  | module.exports = DefinePlugin; |