[6a3a178] | 1 | /*
|
---|
| 2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
| 3 | Author Tobias Koppers @sokra
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | "use strict";
|
---|
| 7 |
|
---|
| 8 | const RuntimeGlobals = require("./RuntimeGlobals");
|
---|
| 9 | const WebpackError = require("./WebpackError");
|
---|
| 10 | const ConstDependency = require("./dependencies/ConstDependency");
|
---|
| 11 | const BasicEvaluatedExpression = require("./javascript/BasicEvaluatedExpression");
|
---|
| 12 | const {
|
---|
| 13 | evaluateToString,
|
---|
| 14 | toConstantDependency
|
---|
| 15 | } = require("./javascript/JavascriptParserHelpers");
|
---|
| 16 | const { provide } = require("./util/MapHelpers");
|
---|
| 17 |
|
---|
| 18 | /** @typedef {import("estree").Expression} Expression */
|
---|
| 19 | /** @typedef {import("./Compiler")} Compiler */
|
---|
| 20 | /** @typedef {import("./NormalModule")} NormalModule */
|
---|
| 21 | /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
|
---|
| 22 | /** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
|
---|
| 23 |
|
---|
| 24 | /** @typedef {null|undefined|RegExp|Function|string|number|boolean|bigint|undefined} CodeValuePrimitive */
|
---|
| 25 | /** @typedef {RecursiveArrayOrRecord<CodeValuePrimitive|RuntimeValue>} CodeValue */
|
---|
| 26 |
|
---|
| 27 | /**
|
---|
| 28 | * @typedef {Object} RuntimeValueOptions
|
---|
| 29 | * @property {string[]=} fileDependencies
|
---|
| 30 | * @property {string[]=} contextDependencies
|
---|
| 31 | * @property {string[]=} missingDependencies
|
---|
| 32 | * @property {string[]=} buildDependencies
|
---|
| 33 | * @property {string|function(): string=} version
|
---|
| 34 | */
|
---|
| 35 |
|
---|
| 36 | class RuntimeValue {
|
---|
| 37 | /**
|
---|
| 38 | * @param {function({ module: NormalModule, key: string, readonly version: string | undefined }): CodeValuePrimitive} fn generator function
|
---|
| 39 | * @param {true | string[] | RuntimeValueOptions=} options options
|
---|
| 40 | */
|
---|
| 41 | constructor(fn, options) {
|
---|
| 42 | this.fn = fn;
|
---|
| 43 | if (Array.isArray(options)) {
|
---|
| 44 | options = {
|
---|
| 45 | fileDependencies: options
|
---|
| 46 | };
|
---|
| 47 | }
|
---|
| 48 | this.options = options || {};
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | get fileDependencies() {
|
---|
| 52 | return this.options === true ? true : this.options.fileDependencies;
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | /**
|
---|
| 56 | * @param {JavascriptParser} parser the parser
|
---|
| 57 | * @param {Map<string, string | Set<string>>} valueCacheVersions valueCacheVersions
|
---|
| 58 | * @param {string} key the defined key
|
---|
| 59 | * @returns {CodeValuePrimitive} code
|
---|
| 60 | */
|
---|
| 61 | exec(parser, valueCacheVersions, key) {
|
---|
| 62 | const buildInfo = parser.state.module.buildInfo;
|
---|
| 63 | if (this.options === true) {
|
---|
| 64 | buildInfo.cacheable = false;
|
---|
| 65 | } else {
|
---|
| 66 | if (this.options.fileDependencies) {
|
---|
| 67 | for (const dep of this.options.fileDependencies) {
|
---|
| 68 | buildInfo.fileDependencies.add(dep);
|
---|
| 69 | }
|
---|
| 70 | }
|
---|
| 71 | if (this.options.contextDependencies) {
|
---|
| 72 | for (const dep of this.options.contextDependencies) {
|
---|
| 73 | buildInfo.contextDependencies.add(dep);
|
---|
| 74 | }
|
---|
| 75 | }
|
---|
| 76 | if (this.options.missingDependencies) {
|
---|
| 77 | for (const dep of this.options.missingDependencies) {
|
---|
| 78 | buildInfo.missingDependencies.add(dep);
|
---|
| 79 | }
|
---|
| 80 | }
|
---|
| 81 | if (this.options.buildDependencies) {
|
---|
| 82 | for (const dep of this.options.buildDependencies) {
|
---|
| 83 | buildInfo.buildDependencies.add(dep);
|
---|
| 84 | }
|
---|
| 85 | }
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | return this.fn({
|
---|
| 89 | module: parser.state.module,
|
---|
| 90 | key,
|
---|
| 91 | get version() {
|
---|
| 92 | return /** @type {string} */ (
|
---|
| 93 | valueCacheVersions.get(VALUE_DEP_PREFIX + key)
|
---|
| 94 | );
|
---|
| 95 | }
|
---|
| 96 | });
|
---|
| 97 | }
|
---|
| 98 |
|
---|
| 99 | getCacheVersion() {
|
---|
| 100 | return this.options === true
|
---|
| 101 | ? undefined
|
---|
| 102 | : (typeof this.options.version === "function"
|
---|
| 103 | ? this.options.version()
|
---|
| 104 | : this.options.version) || "unset";
|
---|
| 105 | }
|
---|
| 106 | }
|
---|
| 107 |
|
---|
| 108 | /**
|
---|
| 109 | * @param {any[]|{[k: string]: any}} obj obj
|
---|
| 110 | * @param {JavascriptParser} parser Parser
|
---|
| 111 | * @param {Map<string, string | Set<string>>} valueCacheVersions valueCacheVersions
|
---|
| 112 | * @param {string} key the defined key
|
---|
| 113 | * @param {RuntimeTemplate} runtimeTemplate the runtime template
|
---|
| 114 | * @param {boolean|undefined|null=} asiSafe asi safe (undefined: unknown, null: unneeded)
|
---|
| 115 | * @returns {string} code converted to string that evaluates
|
---|
| 116 | */
|
---|
| 117 | const stringifyObj = (
|
---|
| 118 | obj,
|
---|
| 119 | parser,
|
---|
| 120 | valueCacheVersions,
|
---|
| 121 | key,
|
---|
| 122 | runtimeTemplate,
|
---|
| 123 | asiSafe
|
---|
| 124 | ) => {
|
---|
| 125 | let code;
|
---|
| 126 | let arr = Array.isArray(obj);
|
---|
| 127 | if (arr) {
|
---|
| 128 | code = `[${obj
|
---|
| 129 | .map(code =>
|
---|
| 130 | toCode(code, parser, valueCacheVersions, key, runtimeTemplate, null)
|
---|
| 131 | )
|
---|
| 132 | .join(",")}]`;
|
---|
| 133 | } else {
|
---|
| 134 | code = `{${Object.keys(obj)
|
---|
| 135 | .map(key => {
|
---|
| 136 | const code = obj[key];
|
---|
| 137 | return (
|
---|
| 138 | JSON.stringify(key) +
|
---|
| 139 | ":" +
|
---|
| 140 | toCode(code, parser, valueCacheVersions, key, runtimeTemplate, null)
|
---|
| 141 | );
|
---|
| 142 | })
|
---|
| 143 | .join(",")}}`;
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | switch (asiSafe) {
|
---|
| 147 | case null:
|
---|
| 148 | return code;
|
---|
| 149 | case true:
|
---|
| 150 | return arr ? code : `(${code})`;
|
---|
| 151 | case false:
|
---|
| 152 | return arr ? `;${code}` : `;(${code})`;
|
---|
| 153 | default:
|
---|
| 154 | return `Object(${code})`;
|
---|
| 155 | }
|
---|
| 156 | };
|
---|
| 157 |
|
---|
| 158 | /**
|
---|
| 159 | * Convert code to a string that evaluates
|
---|
| 160 | * @param {CodeValue} code Code to evaluate
|
---|
| 161 | * @param {JavascriptParser} parser Parser
|
---|
| 162 | * @param {Map<string, string | Set<string>>} valueCacheVersions valueCacheVersions
|
---|
| 163 | * @param {string} key the defined key
|
---|
| 164 | * @param {RuntimeTemplate} runtimeTemplate the runtime template
|
---|
| 165 | * @param {boolean|undefined|null=} asiSafe asi safe (undefined: unknown, null: unneeded)
|
---|
| 166 | * @returns {string} code converted to string that evaluates
|
---|
| 167 | */
|
---|
| 168 | const toCode = (
|
---|
| 169 | code,
|
---|
| 170 | parser,
|
---|
| 171 | valueCacheVersions,
|
---|
| 172 | key,
|
---|
| 173 | runtimeTemplate,
|
---|
| 174 | asiSafe
|
---|
| 175 | ) => {
|
---|
| 176 | if (code === null) {
|
---|
| 177 | return "null";
|
---|
| 178 | }
|
---|
| 179 | if (code === undefined) {
|
---|
| 180 | return "undefined";
|
---|
| 181 | }
|
---|
| 182 | if (Object.is(code, -0)) {
|
---|
| 183 | return "-0";
|
---|
| 184 | }
|
---|
| 185 | if (code instanceof RuntimeValue) {
|
---|
| 186 | return toCode(
|
---|
| 187 | code.exec(parser, valueCacheVersions, key),
|
---|
| 188 | parser,
|
---|
| 189 | valueCacheVersions,
|
---|
| 190 | key,
|
---|
| 191 | runtimeTemplate,
|
---|
| 192 | asiSafe
|
---|
| 193 | );
|
---|
| 194 | }
|
---|
| 195 | if (code instanceof RegExp && code.toString) {
|
---|
| 196 | return code.toString();
|
---|
| 197 | }
|
---|
| 198 | if (typeof code === "function" && code.toString) {
|
---|
| 199 | return "(" + code.toString() + ")";
|
---|
| 200 | }
|
---|
| 201 | if (typeof code === "object") {
|
---|
| 202 | return stringifyObj(
|
---|
| 203 | code,
|
---|
| 204 | parser,
|
---|
| 205 | valueCacheVersions,
|
---|
| 206 | key,
|
---|
| 207 | runtimeTemplate,
|
---|
| 208 | asiSafe
|
---|
| 209 | );
|
---|
| 210 | }
|
---|
| 211 | if (typeof code === "bigint") {
|
---|
| 212 | return runtimeTemplate.supportsBigIntLiteral()
|
---|
| 213 | ? `${code}n`
|
---|
| 214 | : `BigInt("${code}")`;
|
---|
| 215 | }
|
---|
| 216 | return code + "";
|
---|
| 217 | };
|
---|
| 218 |
|
---|
| 219 | const toCacheVersion = code => {
|
---|
| 220 | if (code === null) {
|
---|
| 221 | return "null";
|
---|
| 222 | }
|
---|
| 223 | if (code === undefined) {
|
---|
| 224 | return "undefined";
|
---|
| 225 | }
|
---|
| 226 | if (Object.is(code, -0)) {
|
---|
| 227 | return "-0";
|
---|
| 228 | }
|
---|
| 229 | if (code instanceof RuntimeValue) {
|
---|
| 230 | return code.getCacheVersion();
|
---|
| 231 | }
|
---|
| 232 | if (code instanceof RegExp && code.toString) {
|
---|
| 233 | return code.toString();
|
---|
| 234 | }
|
---|
| 235 | if (typeof code === "function" && code.toString) {
|
---|
| 236 | return "(" + code.toString() + ")";
|
---|
| 237 | }
|
---|
| 238 | if (typeof code === "object") {
|
---|
| 239 | const items = Object.keys(code).map(key => ({
|
---|
| 240 | key,
|
---|
| 241 | value: toCacheVersion(code[key])
|
---|
| 242 | }));
|
---|
| 243 | if (items.some(({ value }) => value === undefined)) return undefined;
|
---|
| 244 | return `{${items.map(({ key, value }) => `${key}: ${value}`).join(", ")}}`;
|
---|
| 245 | }
|
---|
| 246 | if (typeof code === "bigint") {
|
---|
| 247 | return `${code}n`;
|
---|
| 248 | }
|
---|
| 249 | return code + "";
|
---|
| 250 | };
|
---|
| 251 |
|
---|
| 252 | const VALUE_DEP_PREFIX = "webpack/DefinePlugin ";
|
---|
| 253 | const VALUE_DEP_MAIN = "webpack/DefinePlugin";
|
---|
| 254 |
|
---|
| 255 | class DefinePlugin {
|
---|
| 256 | /**
|
---|
| 257 | * Create a new define plugin
|
---|
| 258 | * @param {Record<string, CodeValue>} definitions A map of global object definitions
|
---|
| 259 | */
|
---|
| 260 | constructor(definitions) {
|
---|
| 261 | this.definitions = definitions;
|
---|
| 262 | }
|
---|
| 263 |
|
---|
| 264 | /**
|
---|
| 265 | * @param {function({ module: NormalModule, key: string, readonly version: string | undefined }): CodeValuePrimitive} fn generator function
|
---|
| 266 | * @param {true | string[] | RuntimeValueOptions=} options options
|
---|
| 267 | * @returns {RuntimeValue} runtime value
|
---|
| 268 | */
|
---|
| 269 | static runtimeValue(fn, options) {
|
---|
| 270 | return new RuntimeValue(fn, options);
|
---|
| 271 | }
|
---|
| 272 |
|
---|
| 273 | /**
|
---|
| 274 | * Apply the plugin
|
---|
| 275 | * @param {Compiler} compiler the compiler instance
|
---|
| 276 | * @returns {void}
|
---|
| 277 | */
|
---|
| 278 | apply(compiler) {
|
---|
| 279 | const definitions = this.definitions;
|
---|
| 280 | compiler.hooks.compilation.tap(
|
---|
| 281 | "DefinePlugin",
|
---|
| 282 | (compilation, { normalModuleFactory }) => {
|
---|
| 283 | compilation.dependencyTemplates.set(
|
---|
| 284 | ConstDependency,
|
---|
| 285 | new ConstDependency.Template()
|
---|
| 286 | );
|
---|
| 287 | const { runtimeTemplate } = compilation;
|
---|
| 288 |
|
---|
| 289 | const mainValue = /** @type {Set<string>} */ (
|
---|
| 290 | provide(
|
---|
| 291 | compilation.valueCacheVersions,
|
---|
| 292 | VALUE_DEP_MAIN,
|
---|
| 293 | () => new Set()
|
---|
| 294 | )
|
---|
| 295 | );
|
---|
| 296 |
|
---|
| 297 | /**
|
---|
| 298 | * Handler
|
---|
| 299 | * @param {JavascriptParser} parser Parser
|
---|
| 300 | * @returns {void}
|
---|
| 301 | */
|
---|
| 302 | const handler = parser => {
|
---|
| 303 | parser.hooks.program.tap("DefinePlugin", () => {
|
---|
| 304 | const { buildInfo } = parser.state.module;
|
---|
| 305 | if (!buildInfo.valueDependencies)
|
---|
| 306 | buildInfo.valueDependencies = new Map();
|
---|
| 307 | buildInfo.valueDependencies.set(VALUE_DEP_MAIN, mainValue);
|
---|
| 308 | });
|
---|
| 309 |
|
---|
| 310 | const addValueDependency = key => {
|
---|
| 311 | const { buildInfo } = parser.state.module;
|
---|
| 312 | buildInfo.valueDependencies.set(
|
---|
| 313 | VALUE_DEP_PREFIX + key,
|
---|
| 314 | compilation.valueCacheVersions.get(VALUE_DEP_PREFIX + key)
|
---|
| 315 | );
|
---|
| 316 | };
|
---|
| 317 |
|
---|
| 318 | const withValueDependency =
|
---|
| 319 | (key, fn) =>
|
---|
| 320 | (...args) => {
|
---|
| 321 | addValueDependency(key);
|
---|
| 322 | return fn(...args);
|
---|
| 323 | };
|
---|
| 324 |
|
---|
| 325 | /**
|
---|
| 326 | * Walk definitions
|
---|
| 327 | * @param {Object} definitions Definitions map
|
---|
| 328 | * @param {string} prefix Prefix string
|
---|
| 329 | * @returns {void}
|
---|
| 330 | */
|
---|
| 331 | const walkDefinitions = (definitions, prefix) => {
|
---|
| 332 | Object.keys(definitions).forEach(key => {
|
---|
| 333 | const code = definitions[key];
|
---|
| 334 | if (
|
---|
| 335 | code &&
|
---|
| 336 | typeof code === "object" &&
|
---|
| 337 | !(code instanceof RuntimeValue) &&
|
---|
| 338 | !(code instanceof RegExp)
|
---|
| 339 | ) {
|
---|
| 340 | walkDefinitions(code, prefix + key + ".");
|
---|
| 341 | applyObjectDefine(prefix + key, code);
|
---|
| 342 | return;
|
---|
| 343 | }
|
---|
| 344 | applyDefineKey(prefix, key);
|
---|
| 345 | applyDefine(prefix + key, code);
|
---|
| 346 | });
|
---|
| 347 | };
|
---|
| 348 |
|
---|
| 349 | /**
|
---|
| 350 | * Apply define key
|
---|
| 351 | * @param {string} prefix Prefix
|
---|
| 352 | * @param {string} key Key
|
---|
| 353 | * @returns {void}
|
---|
| 354 | */
|
---|
| 355 | const applyDefineKey = (prefix, key) => {
|
---|
| 356 | const splittedKey = key.split(".");
|
---|
| 357 | splittedKey.slice(1).forEach((_, i) => {
|
---|
| 358 | const fullKey = prefix + splittedKey.slice(0, i + 1).join(".");
|
---|
| 359 | parser.hooks.canRename.for(fullKey).tap("DefinePlugin", () => {
|
---|
| 360 | addValueDependency(key);
|
---|
| 361 | return true;
|
---|
| 362 | });
|
---|
| 363 | });
|
---|
| 364 | };
|
---|
| 365 |
|
---|
| 366 | /**
|
---|
| 367 | * Apply Code
|
---|
| 368 | * @param {string} key Key
|
---|
| 369 | * @param {CodeValue} code Code
|
---|
| 370 | * @returns {void}
|
---|
| 371 | */
|
---|
| 372 | const applyDefine = (key, code) => {
|
---|
| 373 | const originalKey = key;
|
---|
| 374 | const isTypeof = /^typeof\s+/.test(key);
|
---|
| 375 | if (isTypeof) key = key.replace(/^typeof\s+/, "");
|
---|
| 376 | let recurse = false;
|
---|
| 377 | let recurseTypeof = false;
|
---|
| 378 | if (!isTypeof) {
|
---|
| 379 | parser.hooks.canRename.for(key).tap("DefinePlugin", () => {
|
---|
| 380 | addValueDependency(originalKey);
|
---|
| 381 | return true;
|
---|
| 382 | });
|
---|
| 383 | parser.hooks.evaluateIdentifier
|
---|
| 384 | .for(key)
|
---|
| 385 | .tap("DefinePlugin", expr => {
|
---|
| 386 | /**
|
---|
| 387 | * this is needed in case there is a recursion in the DefinePlugin
|
---|
| 388 | * to prevent an endless recursion
|
---|
| 389 | * e.g.: new DefinePlugin({
|
---|
| 390 | * "a": "b",
|
---|
| 391 | * "b": "a"
|
---|
| 392 | * });
|
---|
| 393 | */
|
---|
| 394 | if (recurse) return;
|
---|
| 395 | addValueDependency(originalKey);
|
---|
| 396 | recurse = true;
|
---|
| 397 | const res = parser.evaluate(
|
---|
| 398 | toCode(
|
---|
| 399 | code,
|
---|
| 400 | parser,
|
---|
| 401 | compilation.valueCacheVersions,
|
---|
| 402 | key,
|
---|
| 403 | runtimeTemplate,
|
---|
| 404 | null
|
---|
| 405 | )
|
---|
| 406 | );
|
---|
| 407 | recurse = false;
|
---|
| 408 | res.setRange(expr.range);
|
---|
| 409 | return res;
|
---|
| 410 | });
|
---|
| 411 | parser.hooks.expression.for(key).tap("DefinePlugin", expr => {
|
---|
| 412 | addValueDependency(originalKey);
|
---|
| 413 | const strCode = toCode(
|
---|
| 414 | code,
|
---|
| 415 | parser,
|
---|
| 416 | compilation.valueCacheVersions,
|
---|
| 417 | originalKey,
|
---|
| 418 | runtimeTemplate,
|
---|
| 419 | !parser.isAsiPosition(expr.range[0])
|
---|
| 420 | );
|
---|
| 421 | if (/__webpack_require__\s*(!?\.)/.test(strCode)) {
|
---|
| 422 | return toConstantDependency(parser, strCode, [
|
---|
| 423 | RuntimeGlobals.require
|
---|
| 424 | ])(expr);
|
---|
| 425 | } else if (/__webpack_require__/.test(strCode)) {
|
---|
| 426 | return toConstantDependency(parser, strCode, [
|
---|
| 427 | RuntimeGlobals.requireScope
|
---|
| 428 | ])(expr);
|
---|
| 429 | } else {
|
---|
| 430 | return toConstantDependency(parser, strCode)(expr);
|
---|
| 431 | }
|
---|
| 432 | });
|
---|
| 433 | }
|
---|
| 434 | parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", expr => {
|
---|
| 435 | /**
|
---|
| 436 | * this is needed in case there is a recursion in the DefinePlugin
|
---|
| 437 | * to prevent an endless recursion
|
---|
| 438 | * e.g.: new DefinePlugin({
|
---|
| 439 | * "typeof a": "typeof b",
|
---|
| 440 | * "typeof b": "typeof a"
|
---|
| 441 | * });
|
---|
| 442 | */
|
---|
| 443 | if (recurseTypeof) return;
|
---|
| 444 | recurseTypeof = true;
|
---|
| 445 | addValueDependency(originalKey);
|
---|
| 446 | const codeCode = toCode(
|
---|
| 447 | code,
|
---|
| 448 | parser,
|
---|
| 449 | compilation.valueCacheVersions,
|
---|
| 450 | originalKey,
|
---|
| 451 | runtimeTemplate,
|
---|
| 452 | null
|
---|
| 453 | );
|
---|
| 454 | const typeofCode = isTypeof
|
---|
| 455 | ? codeCode
|
---|
| 456 | : "typeof (" + codeCode + ")";
|
---|
| 457 | const res = parser.evaluate(typeofCode);
|
---|
| 458 | recurseTypeof = false;
|
---|
| 459 | res.setRange(expr.range);
|
---|
| 460 | return res;
|
---|
| 461 | });
|
---|
| 462 | parser.hooks.typeof.for(key).tap("DefinePlugin", expr => {
|
---|
| 463 | addValueDependency(originalKey);
|
---|
| 464 | const codeCode = toCode(
|
---|
| 465 | code,
|
---|
| 466 | parser,
|
---|
| 467 | compilation.valueCacheVersions,
|
---|
| 468 | originalKey,
|
---|
| 469 | runtimeTemplate,
|
---|
| 470 | null
|
---|
| 471 | );
|
---|
| 472 | const typeofCode = isTypeof
|
---|
| 473 | ? codeCode
|
---|
| 474 | : "typeof (" + codeCode + ")";
|
---|
| 475 | const res = parser.evaluate(typeofCode);
|
---|
| 476 | if (!res.isString()) return;
|
---|
| 477 | return toConstantDependency(
|
---|
| 478 | parser,
|
---|
| 479 | JSON.stringify(res.string)
|
---|
| 480 | ).bind(parser)(expr);
|
---|
| 481 | });
|
---|
| 482 | };
|
---|
| 483 |
|
---|
| 484 | /**
|
---|
| 485 | * Apply Object
|
---|
| 486 | * @param {string} key Key
|
---|
| 487 | * @param {Object} obj Object
|
---|
| 488 | * @returns {void}
|
---|
| 489 | */
|
---|
| 490 | const applyObjectDefine = (key, obj) => {
|
---|
| 491 | parser.hooks.canRename.for(key).tap("DefinePlugin", () => {
|
---|
| 492 | addValueDependency(key);
|
---|
| 493 | return true;
|
---|
| 494 | });
|
---|
| 495 | parser.hooks.evaluateIdentifier
|
---|
| 496 | .for(key)
|
---|
| 497 | .tap("DefinePlugin", expr => {
|
---|
| 498 | addValueDependency(key);
|
---|
| 499 | return new BasicEvaluatedExpression()
|
---|
| 500 | .setTruthy()
|
---|
| 501 | .setSideEffects(false)
|
---|
| 502 | .setRange(expr.range);
|
---|
| 503 | });
|
---|
| 504 | parser.hooks.evaluateTypeof
|
---|
| 505 | .for(key)
|
---|
| 506 | .tap(
|
---|
| 507 | "DefinePlugin",
|
---|
| 508 | withValueDependency(key, evaluateToString("object"))
|
---|
| 509 | );
|
---|
| 510 | parser.hooks.expression.for(key).tap("DefinePlugin", expr => {
|
---|
| 511 | addValueDependency(key);
|
---|
| 512 | const strCode = stringifyObj(
|
---|
| 513 | obj,
|
---|
| 514 | parser,
|
---|
| 515 | compilation.valueCacheVersions,
|
---|
| 516 | key,
|
---|
| 517 | runtimeTemplate,
|
---|
| 518 | !parser.isAsiPosition(expr.range[0])
|
---|
| 519 | );
|
---|
| 520 |
|
---|
| 521 | if (/__webpack_require__\s*(!?\.)/.test(strCode)) {
|
---|
| 522 | return toConstantDependency(parser, strCode, [
|
---|
| 523 | RuntimeGlobals.require
|
---|
| 524 | ])(expr);
|
---|
| 525 | } else if (/__webpack_require__/.test(strCode)) {
|
---|
| 526 | return toConstantDependency(parser, strCode, [
|
---|
| 527 | RuntimeGlobals.requireScope
|
---|
| 528 | ])(expr);
|
---|
| 529 | } else {
|
---|
| 530 | return toConstantDependency(parser, strCode)(expr);
|
---|
| 531 | }
|
---|
| 532 | });
|
---|
| 533 | parser.hooks.typeof
|
---|
| 534 | .for(key)
|
---|
| 535 | .tap(
|
---|
| 536 | "DefinePlugin",
|
---|
| 537 | withValueDependency(
|
---|
| 538 | key,
|
---|
| 539 | toConstantDependency(parser, JSON.stringify("object"))
|
---|
| 540 | )
|
---|
| 541 | );
|
---|
| 542 | };
|
---|
| 543 |
|
---|
| 544 | walkDefinitions(definitions, "");
|
---|
| 545 | };
|
---|
| 546 |
|
---|
| 547 | normalModuleFactory.hooks.parser
|
---|
| 548 | .for("javascript/auto")
|
---|
| 549 | .tap("DefinePlugin", handler);
|
---|
| 550 | normalModuleFactory.hooks.parser
|
---|
| 551 | .for("javascript/dynamic")
|
---|
| 552 | .tap("DefinePlugin", handler);
|
---|
| 553 | normalModuleFactory.hooks.parser
|
---|
| 554 | .for("javascript/esm")
|
---|
| 555 | .tap("DefinePlugin", handler);
|
---|
| 556 |
|
---|
| 557 | /**
|
---|
| 558 | * Walk definitions
|
---|
| 559 | * @param {Object} definitions Definitions map
|
---|
| 560 | * @param {string} prefix Prefix string
|
---|
| 561 | * @returns {void}
|
---|
| 562 | */
|
---|
| 563 | const walkDefinitionsForValues = (definitions, prefix) => {
|
---|
| 564 | Object.keys(definitions).forEach(key => {
|
---|
| 565 | const code = definitions[key];
|
---|
| 566 | const version = toCacheVersion(code);
|
---|
| 567 | const name = VALUE_DEP_PREFIX + prefix + key;
|
---|
| 568 | mainValue.add(name);
|
---|
| 569 | const oldVersion = compilation.valueCacheVersions.get(name);
|
---|
| 570 | if (oldVersion === undefined) {
|
---|
| 571 | compilation.valueCacheVersions.set(name, version);
|
---|
| 572 | } else if (oldVersion !== version) {
|
---|
| 573 | const warning = new WebpackError(
|
---|
| 574 | `DefinePlugin\nConflicting values for '${prefix + key}'`
|
---|
| 575 | );
|
---|
| 576 | warning.details = `'${oldVersion}' !== '${version}'`;
|
---|
| 577 | warning.hideStack = true;
|
---|
| 578 | compilation.warnings.push(warning);
|
---|
| 579 | }
|
---|
| 580 | if (
|
---|
| 581 | code &&
|
---|
| 582 | typeof code === "object" &&
|
---|
| 583 | !(code instanceof RuntimeValue) &&
|
---|
| 584 | !(code instanceof RegExp)
|
---|
| 585 | ) {
|
---|
| 586 | walkDefinitionsForValues(code, prefix + key + ".");
|
---|
| 587 | }
|
---|
| 588 | });
|
---|
| 589 | };
|
---|
| 590 |
|
---|
| 591 | walkDefinitionsForValues(definitions, "");
|
---|
| 592 | }
|
---|
| 593 | );
|
---|
| 594 | }
|
---|
| 595 | }
|
---|
| 596 | module.exports = DefinePlugin;
|
---|