mirror of https://github.com/webpack/webpack.git
				
				
				
			
		
			
				
	
	
		
			668 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			668 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| /*
 | |
| 	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;
 |