webpack 5.108.4 → 5.109.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/bin/webpack.js +12 -0
  2. package/lib/APIPlugin.js +48 -29
  3. package/lib/CacheFacade.js +8 -0
  4. package/lib/ChunkGraph.js +17 -15
  5. package/lib/ChunkGroup.js +1 -0
  6. package/lib/CompatibilityPlugin.js +62 -29
  7. package/lib/Compilation.js +58 -6
  8. package/lib/ConstPlugin.js +11 -11
  9. package/lib/ContextModule.js +239 -6
  10. package/lib/ContextModuleFactory.js +139 -14
  11. package/lib/DefinePlugin.js +433 -112
  12. package/lib/Entrypoint.js +1 -1
  13. package/lib/ExportsInfo.js +22 -5
  14. package/lib/ExportsInfoApiPlugin.js +2 -2
  15. package/lib/ExternalModule.js +107 -5
  16. package/lib/ExternalModuleFactoryPlugin.js +20 -1
  17. package/lib/FileSystemInfo.js +256 -100
  18. package/lib/FlagDependencyUsagePlugin.js +33 -12
  19. package/lib/HotModuleReplacementPlugin.js +18 -15
  20. package/lib/InitFragment.js +20 -32
  21. package/lib/Module.js +3 -0
  22. package/lib/ModuleFilenameHelpers.js +2 -2
  23. package/lib/ModuleTypeConstants.js +8 -1
  24. package/lib/MultiCompiler.js +13 -2
  25. package/lib/MultiWatching.js +1 -0
  26. package/lib/NodeStuffPlugin.js +51 -33
  27. package/lib/NormalModule.js +175 -401
  28. package/lib/NormalModuleFactory.js +76 -2
  29. package/lib/ProgressPlugin.js +211 -119
  30. package/lib/ProvidePlugin.js +2 -2
  31. package/lib/RuntimeGlobals.js +47 -0
  32. package/lib/RuntimePlugin.js +67 -107
  33. package/lib/RuntimeTemplate.js +304 -16
  34. package/lib/Template.js +23 -3
  35. package/lib/UseStrictPlugin.js +1 -1
  36. package/lib/WebpackIsIncludedPlugin.js +1 -1
  37. package/lib/WebpackOptionsApply.js +24 -19
  38. package/lib/asset/AssetGenerator.js +110 -28
  39. package/lib/asset/AssetModulesPlugin.js +92 -2
  40. package/lib/asset/WebManifestGenerator.js +164 -0
  41. package/lib/asset/WebManifestParser.js +130 -0
  42. package/lib/async-modules/AwaitDependenciesInitFragment.js +14 -4
  43. package/lib/async-modules/isGeneratorLowered.js +26 -0
  44. package/lib/cache/PackFileCacheStrategy.js +9 -3
  45. package/lib/config/browserslistTargetHandler.js +40 -0
  46. package/lib/config/defaults.js +219 -29
  47. package/lib/config/normalization.js +26 -0
  48. package/lib/config/target.js +9 -1
  49. package/lib/container/HoistContainerReferencesPlugin.js +47 -55
  50. package/lib/css/CssGenerator.js +40 -31
  51. package/lib/css/CssLoadingRuntimeModule.js +5 -1
  52. package/lib/css/CssModulesPlugin.js +13 -0
  53. package/lib/css/CssParser.js +729 -313
  54. package/lib/css/syntax.js +1371 -861
  55. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -6
  56. package/lib/dependencies/AMDPlugin.js +2 -2
  57. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +13 -13
  58. package/lib/dependencies/CommonJsDependencyHelpers.js +39 -0
  59. package/lib/dependencies/CommonJsExportRequireDependency.js +19 -0
  60. package/lib/dependencies/CommonJsExportsDependency.js +47 -2
  61. package/lib/dependencies/CommonJsExportsParserPlugin.js +10 -10
  62. package/lib/dependencies/CommonJsImportsParserPlugin.js +18 -18
  63. package/lib/dependencies/CommonJsPlugin.js +2 -2
  64. package/lib/dependencies/CommonJsRequireDependency.js +26 -1
  65. package/lib/dependencies/CommonJsSelfReferenceDependency.js +32 -1
  66. package/lib/dependencies/ContextDependencyHelpers.js +3 -3
  67. package/lib/dependencies/CreateRequireParserPlugin.js +6 -6
  68. package/lib/dependencies/CssIcssExportDependency.js +162 -71
  69. package/lib/dependencies/CssUrlDependency.js +35 -4
  70. package/lib/dependencies/ExternalModuleInitFragmentDependency.js +2 -2
  71. package/lib/dependencies/HarmonyCompatibilityDependency.js +32 -14
  72. package/lib/dependencies/HarmonyDetectionParserPlugin.js +43 -13
  73. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +2 -1
  74. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +7 -19
  75. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +17 -9
  76. package/lib/dependencies/HarmonyImportDependency.js +13 -2
  77. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +11 -11
  78. package/lib/dependencies/HarmonyImportSpecifierDependency.js +10 -7
  79. package/lib/dependencies/HarmonyModulesPlugin.js +6 -0
  80. package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +1 -1
  81. package/lib/dependencies/HtmlEntryDependency.js +797 -172
  82. package/lib/dependencies/HtmlSourceDependency.js +26 -0
  83. package/lib/dependencies/ImportDependency.js +43 -1
  84. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +31 -18
  85. package/lib/dependencies/ImportMetaContextPlugin.js +38 -7
  86. package/lib/dependencies/ImportMetaGlobDependency.js +81 -0
  87. package/lib/dependencies/ImportMetaGlobDependencyParserPlugin.js +78 -0
  88. package/lib/dependencies/ImportMetaGlobHelpers.js +660 -0
  89. package/lib/dependencies/ImportMetaPlugin.js +532 -180
  90. package/lib/dependencies/ImportMetaResolveDependency.js +90 -0
  91. package/lib/dependencies/ImportParserPlugin.js +80 -17
  92. package/lib/dependencies/ImportPhase.js +10 -8
  93. package/lib/dependencies/LoaderPlugin.js +5 -1
  94. package/lib/dependencies/RequireContextDependencyParserPlugin.js +1 -1
  95. package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +3 -6
  96. package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +4 -11
  97. package/lib/dependencies/SystemPlugin.js +2 -4
  98. package/lib/dependencies/TopLevelAwaitDependency.js +93 -0
  99. package/lib/dependencies/URLDependency.js +141 -21
  100. package/lib/dependencies/{WorkerPlugin.js → WorkerAndWorkletPlugin.js} +324 -112
  101. package/lib/dependencies/WorkerDependency.js +86 -18
  102. package/lib/dependencies/WorkletDependency.js +278 -0
  103. package/lib/dll/DelegatedModuleFactoryPlugin.js +19 -0
  104. package/lib/errors/EnvironmentNotSupportAsyncWarning.js +1 -1
  105. package/lib/errors/LoaderLoadingError.js +20 -0
  106. package/lib/errors/ModuleParseError.js +39 -22
  107. package/lib/errors/NodeStuffInWebError.js +1 -1
  108. package/lib/esm/ModuleChunkFormatPlugin.js +47 -14
  109. package/lib/esm/ModuleChunkLoadingPlugin.js +8 -1
  110. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +29 -1
  111. package/lib/hmr/lazyCompilationBackend.js +51 -12
  112. package/lib/html/HtmlGenerator.js +907 -15
  113. package/lib/html/HtmlModule.js +2 -2
  114. package/lib/html/HtmlModulesPlugin.js +610 -166
  115. package/lib/html/HtmlParser.js +603 -247
  116. package/lib/html/favicon.svg +1 -0
  117. package/lib/html/syntax.js +3451 -2762
  118. package/lib/ids/IdHelpers.js +25 -11
  119. package/lib/index.js +6 -0
  120. package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +4 -5
  121. package/lib/javascript/BasicEvaluatedExpression.js +366 -48
  122. package/lib/javascript/JavascriptGenerator.js +197 -49
  123. package/lib/javascript/JavascriptModulesPlugin.js +178 -24
  124. package/lib/javascript/JavascriptParser.js +704 -355
  125. package/lib/javascript/JavascriptParserHelpers.js +3 -6
  126. package/lib/javascript/syntax.js +5037 -0
  127. package/lib/library/ModuleLibraryPlugin.js +38 -1
  128. package/lib/loaders/LoaderRunner.js +714 -0
  129. package/lib/loaders/loadLoader.js +100 -0
  130. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +29 -2
  131. package/lib/node/ReadFileCompileWasmPlugin.js +24 -2
  132. package/lib/optimize/AggressiveMergingPlugin.js +19 -15
  133. package/lib/optimize/ConcatenatedModule.js +139 -31
  134. package/lib/optimize/FlagIncludedChunksPlugin.js +13 -3
  135. package/lib/optimize/InnerGraphPlugin.js +50 -30
  136. package/lib/optimize/ModuleConcatenationPlugin.js +139 -24
  137. package/lib/optimize/SideEffectsFlagPlugin.js +86 -43
  138. package/lib/optimize/SplitChunksPlugin.js +146 -44
  139. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +15 -0
  140. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +24 -13
  141. package/lib/prefetch/ResourceHintPlugin.js +687 -0
  142. package/lib/prefetch/ResourceHintRuntimeModule.js +149 -0
  143. package/lib/prefetch/StartupAssetHintRuntimeModule.js +210 -0
  144. package/lib/prefetch/parseResourceHintOptions.js +103 -0
  145. package/lib/rules/RuleSetCompiler.js +114 -0
  146. package/lib/runtime/AsyncModuleGeneratorRuntimeModule.js +56 -0
  147. package/lib/runtime/AsyncModuleRuntimeModule.js +24 -8
  148. package/lib/runtime/AutoPublicPathRuntimeModule.js +7 -1
  149. package/lib/runtime/CommonJsWrapRuntimeModule.js +37 -0
  150. package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +59 -0
  151. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +204 -8
  152. package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +4 -1
  153. package/lib/schemes/HttpUriPlugin.js +40 -1
  154. package/lib/schemes/VirtualUrlPlugin.js +1 -2
  155. package/lib/serialization/BinaryMiddleware.js +270 -938
  156. package/lib/serialization/FileMiddleware.js +29 -3
  157. package/lib/stats/DefaultStatsFactoryPlugin.js +229 -194
  158. package/lib/stats/DefaultStatsPresetPlugin.js +2 -0
  159. package/lib/stats/DefaultStatsPrinterPlugin.js +36 -168
  160. package/lib/stats/StatsFactory.js +46 -17
  161. package/lib/url/URLParserPlugin.js +66 -13
  162. package/lib/util/AsyncQueue.js +122 -72
  163. package/lib/util/SetHelpers.js +1 -1
  164. package/lib/util/StackedMap.js +122 -48
  165. package/lib/util/binarySearchBounds.js +2 -2
  166. package/lib/util/concatenate.js +40 -14
  167. package/lib/util/createHooksRegistry.js +13 -5
  168. package/lib/util/dataURL.js +2 -2
  169. package/lib/util/deterministicGrouping.js +7 -5
  170. package/lib/util/formatSize.js +6 -2
  171. package/lib/util/globUtils.js +710 -0
  172. package/lib/util/identifier.js +23 -6
  173. package/lib/util/implicitTypeLoaderFallback.js +62 -0
  174. package/lib/util/internalSerializables.js +88 -71
  175. package/lib/util/magicComment.js +121 -25
  176. package/lib/util/numberHash.js +2 -2
  177. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +24 -18
  178. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +33 -22
  179. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +79 -16
  180. package/lib/web/FetchCompileAsyncWasmPlugin.js +19 -0
  181. package/lib/web/FetchCompileWasmPlugin.js +14 -0
  182. package/lib/web/JsonpChunkLoadingRuntimeModule.js +2 -0
  183. package/lib/webpack.js +65 -0
  184. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +3 -0
  185. package/module.d.ts +21 -0
  186. package/package.json +12 -11
  187. package/schemas/WebpackOptions.check.js +1 -1
  188. package/schemas/WebpackOptions.json +759 -36
  189. package/schemas/plugins/HtmlParserOptions.check.js +1 -1
  190. package/schemas/plugins/ProgressPlugin.check.js +1 -1
  191. package/schemas/plugins/ProgressPlugin.json +17 -1
  192. package/schemas/plugins/container/ContainerReferencePlugin.check.js +1 -1
  193. package/schemas/plugins/container/ContainerReferencePlugin.json +1 -0
  194. package/schemas/plugins/container/ExternalsType.check.js +1 -1
  195. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  196. package/schemas/plugins/container/ModuleFederationPlugin.json +1 -0
  197. package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +1 -1
  198. package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
  199. package/schemas/plugins/css/CssParserOptions.check.js +1 -1
  200. package/types.d.ts +1212 -99
@@ -86,6 +86,10 @@ class RuntimeValue {
86
86
  const buildInfo = /** @type {BuildInfo} */ (parser.state.module.buildInfo);
87
87
  if (this.options === true) {
88
88
  buildInfo.cacheable = false;
89
+ const reasons =
90
+ buildInfo.notCacheableReasons || (buildInfo.notCacheableReasons = []);
91
+ const reason = `DefinePlugin runtime value ${key}`;
92
+ if (!reasons.includes(reason)) reasons.push(reason);
89
93
  } else {
90
94
  if (this.options.fileDependencies) {
91
95
  for (const dep of this.options.fileDependencies) {
@@ -204,7 +208,7 @@ const stringifyObj = (
204
208
  code = `{${keys
205
209
  .map((key) => {
206
210
  const code = obj[key];
207
- return `${key === "__proto__" ? '["__proto__"]' : JSON.stringify(key)}:${toCode(
211
+ return `${toPropertyKey(key)}:${toCode(
208
212
  code,
209
213
  parser,
210
214
  valueCacheVersions,
@@ -350,10 +354,299 @@ const PLUGIN_NAME = "DefinePlugin";
350
354
  const VALUE_DEP_PREFIX = `webpack/${PLUGIN_NAME} `;
351
355
  const VALUE_DEP_MAIN = `webpack/${PLUGIN_NAME}_hash`;
352
356
  const TYPEOF_OPERATOR_REGEXP = /^typeof\s+/;
357
+ const EMPTY_OBJECT = {};
358
+
359
+ /** @typedef {Map<string, MergedDefinitionNode>} MergedDefinitionMap */
360
+ /** @typedef {CodeValue | MergedDefinitionMap} MergedDefinitionNode */
361
+
362
+ /**
363
+ * Merged view of the definitions of every DefinePlugin instance.
364
+ * @typedef {object} MergedDefinitions
365
+ * @property {Compilation} compilation the compilation
366
+ * @property {Definitions} definitions flat definitions
367
+ * @property {MergedDefinitionMap} root nested view (dotted keys expanded)
368
+ * @property {Map<string, Set<string>>} finalByNestedKey final key segments by nested object key
369
+ * @property {Map<string, Set<string>>} nestedByFinalKey nested object keys by final key segment
370
+ * @property {Map<string, string[]>} keysByPrefix definition keys below each dotted-key prefix
371
+ * @property {boolean} hasRuntimeValue renders are module-dependent (RuntimeValue present)
372
+ * @property {WeakMap<MergedDefinitionMap, string>} codeCache rendered code per node (static trees only)
373
+ * @property {Logger} logger the logger
374
+ */
375
+
376
+ /** @type {WeakMap<Compilation, MergedDefinitions>} */
377
+ const mergedDefinitionsMap = new WeakMap();
378
+
379
+ /**
380
+ * Whether a definition value is a plain object to expand into the nested view.
381
+ * @param {CodeValue} code definition value
382
+ * @returns {code is Definitions} true for a plain object
383
+ */
384
+ const isPlainObjectDefinition = (code) => {
385
+ if (!code || typeof code !== "object" || Array.isArray(code)) return false;
386
+ const proto = Object.getPrototypeOf(code);
387
+ return proto === Object.prototype || proto === null;
388
+ };
389
+
390
+ /**
391
+ * Object literal key code; `__proto__` must be computed to stay an own property.
392
+ * @param {string} key property key
393
+ * @returns {string} property key code
394
+ */
395
+ const toPropertyKey = (key) =>
396
+ key === "__proto__" ? '["__proto__"]' : JSON.stringify(key);
397
+
398
+ /**
399
+ * Whether a definition value contains a RuntimeValue (module-dependent code).
400
+ * @param {CodeValue} value definition value
401
+ * @returns {boolean} true when a RuntimeValue is contained
402
+ */
403
+ const containsRuntimeValue = (value) => {
404
+ if (value instanceof RuntimeValue) return true;
405
+ if (isObjectDefinition(value)) {
406
+ for (const key of Object.keys(value)) {
407
+ if (containsRuntimeValue(value[key])) return true;
408
+ }
409
+ }
410
+ return false;
411
+ };
412
+
413
+ /**
414
+ * Sets a definition value on a node of the nested view, merging plain objects.
415
+ * @param {MergedDefinitionMap} node node
416
+ * @param {string} key key
417
+ * @param {CodeValue} value definition value
418
+ */
419
+ const setMergedValue = (node, key, value) => {
420
+ const existing = node.get(key);
421
+ if (isPlainObjectDefinition(value)) {
422
+ const map =
423
+ existing instanceof Map
424
+ ? existing
425
+ : /** @type {MergedDefinitionMap} */ (new Map());
426
+ if (map !== existing) node.set(key, map);
427
+ for (const k of Object.keys(value)) setMergedValue(map, k, value[k]);
428
+ } else {
429
+ node.set(key, value);
430
+ }
431
+ };
432
+
433
+ /**
434
+ * Inserts a definition key path into the nested view.
435
+ * @param {MergedDefinitionMap} root root node
436
+ * @param {string[]} path dot-separated key path
437
+ * @param {CodeValue} value definition value
438
+ */
439
+ const insertMergedDefinition = (root, path, value) => {
440
+ let node = root;
441
+ for (let i = 0; i < path.length - 1; i++) {
442
+ let next = node.get(path[i]);
443
+ if (next === undefined && !node.has(path[i])) {
444
+ next = /** @type {MergedDefinitionMap} */ (new Map());
445
+ node.set(path[i], next);
446
+ } else if (!(next instanceof Map)) {
447
+ // deeper keys cannot merge into a non-object value
448
+ return;
449
+ }
450
+ node = next;
451
+ }
452
+ setMergedValue(node, path[path.length - 1], value);
453
+ };
454
+
455
+ /**
456
+ * Returns the merged view of all definitions (built once per compilation).
457
+ * @param {Compilation} compilation the compilation
458
+ * @returns {MergedDefinitions} merged definitions
459
+ */
460
+ const getMergedDefinitions = (compilation) => {
461
+ const cached = mergedDefinitionsMap.get(compilation);
462
+ if (cached) return cached;
463
+
464
+ const definitions = DefinePlugin.getCompilationHooks(
465
+ compilation
466
+ ).definitions.call({});
467
+ /** @type {MergedDefinitionMap} */
468
+ const root = new Map();
469
+ /** @type {Map<string, Set<string>>} */
470
+ const finalByNestedKey = new Map();
471
+ /** @type {Map<string, Set<string>>} */
472
+ const nestedByFinalKey = new Map();
473
+ /**
474
+ * @param {Map<string, Set<string>>} map map
475
+ * @param {string} key key
476
+ * @param {string} value value
477
+ */
478
+ const addToMap = (map, key, value) => {
479
+ const set = map.get(key);
480
+ if (set) {
481
+ set.add(value);
482
+ } else {
483
+ map.set(key, new Set([value]));
484
+ }
485
+ };
486
+ let hasRuntimeValue = false;
487
+ /** @type {Map<string, string[]>} */
488
+ const keysByPrefix = new Map();
489
+ for (const key of Object.keys(definitions)) {
490
+ if (TYPEOF_OPERATOR_REGEXP.test(key)) continue;
491
+ const code = definitions[key];
492
+ insertMergedDefinition(root, key.split("."), code);
493
+ if (!hasRuntimeValue && containsRuntimeValue(code)) hasRuntimeValue = true;
494
+ // group this key under every ancestor prefix (value deps of object reads)
495
+ for (
496
+ let idx = key.indexOf(".");
497
+ idx !== -1;
498
+ idx = key.indexOf(".", idx + 1)
499
+ ) {
500
+ const prefix = key.slice(0, idx);
501
+ const keys = keysByPrefix.get(prefix);
502
+ if (keys) {
503
+ keys.push(key);
504
+ } else {
505
+ keysByPrefix.set(prefix, [key]);
506
+ }
507
+ }
508
+ if (!code || typeof code === "object") continue;
509
+ const idx = key.lastIndexOf(".");
510
+ if (idx <= 0 || idx >= key.length - 1) continue;
511
+ const nested = key.slice(0, idx);
512
+ const final = key.slice(idx + 1);
513
+ addToMap(finalByNestedKey, nested, final);
514
+ addToMap(nestedByFinalKey, final, nested);
515
+ }
516
+ const result = {
517
+ compilation,
518
+ definitions,
519
+ root,
520
+ finalByNestedKey,
521
+ nestedByFinalKey,
522
+ keysByPrefix,
523
+ hasRuntimeValue,
524
+ codeCache: new WeakMap(),
525
+ logger: compilation.getLogger("webpack.DefinePlugin")
526
+ };
527
+ mergedDefinitionsMap.set(compilation, result);
528
+ return result;
529
+ };
530
+
531
+ /**
532
+ * Returns the merged definition node for a definition key.
533
+ * @param {Compilation} compilation the compilation
534
+ * @param {string} key definition key
535
+ * @returns {MergedDefinitionNode | undefined} merged node
536
+ */
537
+ const getMergedDefinitionNode = (compilation, key) => {
538
+ /** @type {MergedDefinitionNode | undefined} */
539
+ let node = getMergedDefinitions(compilation).root;
540
+ for (const part of key.split(".")) {
541
+ if (!(node instanceof Map)) return;
542
+ node = node.get(part);
543
+ }
544
+ return node;
545
+ };
546
+
547
+ /**
548
+ * Returns a merged map node converted to an object literal code string
549
+ * (no ASI wrapping). Static renders (no key filter, no RuntimeValue) are
550
+ * cached per compilation.
551
+ * @param {MergedDefinitions} merged merged definitions
552
+ * @param {MergedDefinitionMap} node merged map node
553
+ * @param {JavascriptParser} parser Parser
554
+ * @param {string} key the defined key
555
+ * @param {ObjKeys=} objKeys used keys
556
+ * @returns {string} code
557
+ */
558
+ const stringifyMergedNode = (merged, node, parser, key, objKeys) => {
559
+ const cacheable = objKeys === undefined && !merged.hasRuntimeValue;
560
+ if (cacheable) {
561
+ const cached = merged.codeCache.get(node);
562
+ if (cached !== undefined) return cached;
563
+ }
564
+ let keys = [...node.keys()];
565
+ if (objKeys) {
566
+ keys = objKeys.size === 0 ? [] : keys.filter((k) => objKeys.has(k));
567
+ }
568
+ const code = `{${keys
569
+ .map((k) => {
570
+ const value = /** @type {MergedDefinitionNode} */ (node.get(k));
571
+ return `${toPropertyKey(k)}:${
572
+ value instanceof Map
573
+ ? stringifyMergedNode(merged, value, parser, k)
574
+ : toCode(
575
+ value,
576
+ parser,
577
+ merged.compilation.valueCacheVersions,
578
+ k,
579
+ merged.compilation.runtimeTemplate,
580
+ merged.logger,
581
+ null
582
+ )
583
+ }`;
584
+ })
585
+ .join(",")}}`;
586
+ if (cacheable) merged.codeCache.set(node, code);
587
+ return code;
588
+ };
589
+
590
+ /**
591
+ * Renders a merged definition node to raw code (object literal for map nodes).
592
+ * @param {Compilation} compilation the compilation
593
+ * @param {JavascriptParser} parser Parser
594
+ * @param {MergedDefinitionNode} node merged node
595
+ * @param {string} key the defined key
596
+ * @param {ObjKeys=} objKeys used keys
597
+ * @returns {string} code
598
+ */
599
+ const stringifyMergedDefinition = (compilation, parser, node, key, objKeys) => {
600
+ const merged = getMergedDefinitions(compilation);
601
+ return node instanceof Map
602
+ ? stringifyMergedNode(merged, node, parser, key, objKeys)
603
+ : toCode(
604
+ node,
605
+ parser,
606
+ compilation.valueCacheVersions,
607
+ key,
608
+ compilation.runtimeTemplate,
609
+ merged.logger,
610
+ null
611
+ );
612
+ };
613
+
353
614
  const WEBPACK_REQUIRE_FUNCTION_REGEXP = new RegExp(
354
615
  `${RuntimeGlobals.require}\\s*(!?\\.)`
355
616
  );
356
- const WEBPACK_REQUIRE_IDENTIFIER_REGEXP = new RegExp(RuntimeGlobals.require);
617
+
618
+ /**
619
+ * Runtime requirements of replacement code referencing the require function.
620
+ * @param {string} code replacement code
621
+ * @returns {string[] | undefined} runtime requirements
622
+ */
623
+ const getRuntimeRequirements = (code) => {
624
+ // fast path: most replacement code never references the require function
625
+ if (!code.includes(RuntimeGlobals.require)) return;
626
+ return WEBPACK_REQUIRE_FUNCTION_REGEXP.test(code)
627
+ ? [RuntimeGlobals.require]
628
+ : [RuntimeGlobals.requireScope];
629
+ };
630
+
631
+ /**
632
+ * Prefixes an evaluation error with the offending define key so a bare
633
+ * "Unexpected token" becomes actionable. The original error is mutated and
634
+ * returned (not re-wrapped) so its `loc`/`stack` survive for ModuleParseError's
635
+ * code frame instead of being dumped into the message.
636
+ * @param {string} key the defined key
637
+ * @param {CodeValue} code the defined value
638
+ * @param {unknown} error the original evaluation error
639
+ * @returns {Error} the annotated error
640
+ */
641
+ const annotateEvaluationError = (key, code, error) => {
642
+ const value = typeof code === "string" ? code : JSON.stringify(code);
643
+ const prefix = `DefinePlugin: failed to evaluate value for "${key}" (\`${value}\`)`;
644
+ if (error instanceof Error) {
645
+ error.message = `${prefix}: ${error.message}`;
646
+ return error;
647
+ }
648
+ return new WebpackError(`${prefix}: ${error}`);
649
+ };
357
650
 
358
651
  /**
359
652
  * Defines the define plugin hooks type used by this module.
@@ -400,15 +693,6 @@ class DefinePlugin {
400
693
  ...definitions
401
694
  }));
402
695
 
403
- /**
404
- * @type {Map<string, Set<string>>}
405
- */
406
- const finalByNestedKey = new Map();
407
- /**
408
- * @type {Map<string, Set<string>>}
409
- */
410
- const nestedByFinalKey = new Map();
411
-
412
696
  const logger = compilation.getLogger("webpack.DefinePlugin");
413
697
  compilation.dependencyTemplates.set(
414
698
  ConstDependency,
@@ -428,6 +712,9 @@ class DefinePlugin {
428
712
  * @returns {void}
429
713
  */
430
714
  const handler = (parser) => {
715
+ // built lazily here: every definitions hook is tapped by the time
716
+ // parsers are created, and the result is cached per compilation
717
+ const mergedDefinitions = getMergedDefinitions(compilation);
431
718
  /** @type {Set<string>} */
432
719
  const hooked = new Set();
433
720
  const mainValue =
@@ -506,6 +793,10 @@ class DefinePlugin {
506
793
  const firstKey = splittedKey[0];
507
794
  for (const [i, _] of splittedKey.slice(1).entries()) {
508
795
  const fullKey = prefix + splittedKey.slice(0, i + 1).join(".");
796
+ // `import.meta` is a MetaProperty, not an identifier that can be
797
+ // aliased: an alias declaration would keep the raw MetaProperty
798
+ // in the output, so never enable renaming for its prefixes
799
+ if (fullKey === "import" || fullKey === "import.meta") continue;
509
800
  parser.hooks.canRename.for(fullKey).tap(PLUGIN_NAME, () => {
510
801
  addValueDependency(key);
511
802
  if (
@@ -518,7 +809,9 @@ class DefinePlugin {
518
809
  }
519
810
  if (prefix === "") {
520
811
  const final = splittedKey[splittedKey.length - 1];
521
- const nestedSet = nestedByFinalKey.get(final);
812
+ // aggregated over all instances so keys split across
813
+ // several DefinePlugins can still be destructured together
814
+ const nestedSet = mergedDefinitions.nestedByFinalKey.get(final);
522
815
  if (!nestedSet || nestedSet.size <= 0) return;
523
816
  for (const nested of /** @type {Set<string>} */ (nestedSet)) {
524
817
  if (nested && !hooked.has(nested)) {
@@ -545,17 +838,19 @@ class DefinePlugin {
545
838
  }
546
839
  /** @type {Definitions} */
547
840
  const obj = Object.create(null);
548
- const finalSet = finalByNestedKey.get(nested);
841
+ const finalSet =
842
+ mergedDefinitions.finalByNestedKey.get(nested);
549
843
  for (const { id } of destructed) {
550
844
  const fullKey = `${nested}.${id}`;
551
845
  if (
552
846
  !finalSet ||
553
847
  !finalSet.has(id) ||
554
- !definitions[fullKey]
848
+ !mergedDefinitions.definitions[fullKey]
555
849
  ) {
556
850
  return;
557
851
  }
558
- obj[id] = definitions[fullKey];
852
+ addValueDependency(fullKey);
853
+ obj[id] = mergedDefinitions.definitions[fullKey];
559
854
  }
560
855
  let strCode = stringifyObj(
561
856
  obj,
@@ -643,16 +938,11 @@ class DefinePlugin {
643
938
  strCode = `${parser.scope.inShorthand}:${strCode}`;
644
939
  }
645
940
 
646
- if (WEBPACK_REQUIRE_FUNCTION_REGEXP.test(strCode)) {
647
- return toConstantDependency(parser, strCode, [
648
- RuntimeGlobals.require
649
- ])(expr);
650
- } else if (WEBPACK_REQUIRE_IDENTIFIER_REGEXP.test(strCode)) {
651
- return toConstantDependency(parser, strCode, [
652
- RuntimeGlobals.requireScope
653
- ])(expr);
654
- }
655
- return toConstantDependency(parser, strCode)(expr);
941
+ return toConstantDependency(
942
+ parser,
943
+ strCode,
944
+ getRuntimeRequirements(strCode)
945
+ )(expr);
656
946
  });
657
947
  }
658
948
  parser.hooks.evaluateTypeof.for(key).tap(PLUGIN_NAME, (expr) => {
@@ -684,17 +974,23 @@ class DefinePlugin {
684
974
  });
685
975
  parser.hooks.typeof.for(key).tap(PLUGIN_NAME, (expr) => {
686
976
  addValueDependency(originalKey);
687
- const codeCode = toCode(
688
- code,
689
- parser,
690
- compilation.valueCacheVersions,
691
- originalKey,
692
- runtimeTemplate,
693
- logger,
694
- null
695
- );
696
- const typeofCode = isTypeof ? codeCode : `typeof (${codeCode})`;
697
- const res = parser.evaluate(typeofCode);
977
+ /** @type {BasicEvaluatedExpression} */
978
+ let res;
979
+ try {
980
+ const codeCode = toCode(
981
+ code,
982
+ parser,
983
+ compilation.valueCacheVersions,
984
+ originalKey,
985
+ runtimeTemplate,
986
+ logger,
987
+ null
988
+ );
989
+ const typeofCode = isTypeof ? codeCode : `typeof (${codeCode})`;
990
+ res = parser.evaluate(typeofCode);
991
+ } catch (err) {
992
+ throw annotateEvaluationError(originalKey, code, err);
993
+ }
698
994
  if (!res.isString()) return;
699
995
  return toConstantDependency(
700
996
  parser,
@@ -710,6 +1006,27 @@ class DefinePlugin {
710
1006
  * @returns {void}
711
1007
  */
712
1008
  const applyObjectDefine = (key, obj) => {
1009
+ const mergedNode = getMergedDefinitionNode(compilation, key);
1010
+ /** @type {MergedDefinitionNode} */
1011
+ const definition =
1012
+ mergedNode === undefined
1013
+ ? /** @type {CodeValue} */ (obj)
1014
+ : mergedNode;
1015
+ // value dependencies of a whole-object read: the key itself and
1016
+ // every dotted definition key below it (from any instance)
1017
+ /** @type {[string, ValueCacheVersion][]} */
1018
+ const objectValueDependencies = [];
1019
+ for (const defKey of [
1020
+ key,
1021
+ ...(mergedDefinitions.keysByPrefix.get(key) || [])
1022
+ ]) {
1023
+ const name = VALUE_DEP_PREFIX + defKey;
1024
+ objectValueDependencies.push([
1025
+ name,
1026
+ /** @type {ValueCacheVersion} */
1027
+ (compilation.valueCacheVersions.get(name))
1028
+ ]);
1029
+ }
713
1030
  parser.hooks.canRename.for(key).tap(PLUGIN_NAME, () => {
714
1031
  addValueDependency(key);
715
1032
  return true;
@@ -737,32 +1054,55 @@ class DefinePlugin {
737
1054
  }
738
1055
  );
739
1056
  parser.hooks.expression.for(key).tap(PLUGIN_NAME, (expr) => {
740
- addValueDependency(key);
741
- let strCode = stringifyObj(
742
- obj,
743
- parser,
744
- compilation.valueCacheVersions,
745
- key,
746
- runtimeTemplate,
747
- logger,
748
- !parser.isAsiPosition(/** @type {Range} */ (expr.range)[0]),
749
- getObjKeys(parser.destructuringAssignmentPropertiesFor(expr))
1057
+ const valueDependencies =
1058
+ /** @type {NonNullable<NormalModuleBuildInfo["valueDependencies"]>} */
1059
+ (
1060
+ /** @type {NormalModuleBuildInfo} */
1061
+ (parser.state.module.buildInfo).valueDependencies
1062
+ );
1063
+ for (const [name, version] of objectValueDependencies) {
1064
+ valueDependencies.set(name, version);
1065
+ }
1066
+ // render the merged view so dotted keys (of any instance)
1067
+ // are part of whole-object and destructured reads
1068
+ const objKeys = getObjKeys(
1069
+ parser.destructuringAssignmentPropertiesFor(expr)
750
1070
  );
1071
+ const asiSafe = !parser.isAsiPosition(
1072
+ /** @type {Range} */ (expr.range)[0]
1073
+ );
1074
+ let strCode;
1075
+ if (definition instanceof Map) {
1076
+ const code = stringifyMergedNode(
1077
+ mergedDefinitions,
1078
+ definition,
1079
+ parser,
1080
+ key,
1081
+ objKeys
1082
+ );
1083
+ strCode = asiSafe ? `(${code})` : `;(${code})`;
1084
+ } else {
1085
+ strCode = toCode(
1086
+ definition,
1087
+ parser,
1088
+ compilation.valueCacheVersions,
1089
+ key,
1090
+ runtimeTemplate,
1091
+ logger,
1092
+ asiSafe,
1093
+ objKeys
1094
+ );
1095
+ }
751
1096
 
752
1097
  if (parser.scope.inShorthand) {
753
1098
  strCode = `${parser.scope.inShorthand}:${strCode}`;
754
1099
  }
755
1100
 
756
- if (WEBPACK_REQUIRE_FUNCTION_REGEXP.test(strCode)) {
757
- return toConstantDependency(parser, strCode, [
758
- RuntimeGlobals.require
759
- ])(expr);
760
- } else if (WEBPACK_REQUIRE_IDENTIFIER_REGEXP.test(strCode)) {
761
- return toConstantDependency(parser, strCode, [
762
- RuntimeGlobals.requireScope
763
- ])(expr);
764
- }
765
- return toConstantDependency(parser, strCode)(expr);
1101
+ return toConstantDependency(
1102
+ parser,
1103
+ strCode,
1104
+ getRuntimeRequirements(strCode)
1105
+ )(expr);
766
1106
  });
767
1107
  // A property access not defined on the object resolves to `undefined`
768
1108
  // and the whole object is never inlined (issue #15559). Keyed by the
@@ -775,10 +1115,11 @@ class DefinePlugin {
775
1115
  const chainPrefix = chainParts.slice(isMeta ? 2 : 1);
776
1116
  /**
777
1117
  * Whether a member chain reads a property that is not defined.
1118
+ * Walks the merged view so dotted keys of every instance count.
778
1119
  * Collects every define key consulted so the caller can record a
779
1120
  * value dependency on each (a sibling key like `OBJECT.SUB2` affects
780
1121
  * the result even though `OBJECT` registered the handler).
781
- * `member in value` keeps inherited members (e.g. `toString`) defined.
1122
+ * Inherited members (e.g. `toString`) stay defined.
782
1123
  * @param {Members} members chain members (after the root)
783
1124
  * @param {string[]} deps consulted define keys (mutated)
784
1125
  * @returns {boolean} true when the access resolves to `undefined`
@@ -788,24 +1129,40 @@ class DefinePlugin {
788
1129
  for (let i = 0; i < chainPrefix.length; i++) {
789
1130
  if (members[i] !== chainPrefix[i]) return false;
790
1131
  }
791
- /** @type {CodeValue} */
792
- let value = /** @type {CodeValue} */ (obj);
1132
+ /** @type {MergedDefinitionNode | undefined} */
1133
+ let value = definition;
793
1134
  let path = key;
794
1135
  for (let i = chainPrefix.length; i < members.length; i++) {
795
- // a leaf with members left is a real property access on a value
796
- if (!isObjectDefinition(value)) return false;
797
1136
  const member = members[i];
798
1137
  const nextPath = `${path}.${member}`;
799
- if (member in value) {
800
- value = value[member];
801
- } else if (
802
- Object.prototype.hasOwnProperty.call(definitions, nextPath)
803
- ) {
804
- // defined via a dotted sibling key, e.g. `OBJECT.SUB2`
805
- deps.push(nextPath);
806
- value = definitions[nextPath];
1138
+ if (value instanceof Map) {
1139
+ if (value.has(member)) {
1140
+ deps.push(nextPath);
1141
+ value = value.get(member);
1142
+ } else if (member in EMPTY_OBJECT) {
1143
+ return false;
1144
+ } else {
1145
+ return true;
1146
+ }
1147
+ } else if (isObjectDefinition(value)) {
1148
+ // non-expandable object leaf (e.g. an array)
1149
+ if (member in value) {
1150
+ value = /** @type {Definitions} */ (value)[member];
1151
+ } else if (
1152
+ Object.prototype.hasOwnProperty.call(
1153
+ mergedDefinitions.definitions,
1154
+ nextPath
1155
+ )
1156
+ ) {
1157
+ // defined via a dotted sibling key, e.g. `OBJECT.SUB2`
1158
+ deps.push(nextPath);
1159
+ value = mergedDefinitions.definitions[nextPath];
1160
+ } else {
1161
+ return true;
1162
+ }
807
1163
  } else {
808
- return true;
1164
+ // a leaf with members left is a real property access on a value
1165
+ return false;
809
1166
  }
810
1167
  path = nextPath;
811
1168
  }
@@ -891,48 +1248,6 @@ class DefinePlugin {
891
1248
  }
892
1249
  };
893
1250
 
894
- /**
895
- * Walk definitions for keys.
896
- * @param {Definitions} definitions Definitions map
897
- * @returns {void}
898
- */
899
- const walkDefinitionsForKeys = (definitions) => {
900
- /**
901
- * Adds the provided map to the define plugin.
902
- * @param {Map<string, Set<string>>} map Map
903
- * @param {string} key key
904
- * @param {string} value v
905
- * @returns {void}
906
- */
907
- const addToMap = (map, key, value) => {
908
- if (map.has(key)) {
909
- /** @type {Set<string>} */
910
- (map.get(key)).add(value);
911
- } else {
912
- map.set(key, new Set([value]));
913
- }
914
- };
915
- for (const key of Object.keys(definitions)) {
916
- const code = definitions[key];
917
- if (
918
- !code ||
919
- typeof code === "object" ||
920
- TYPEOF_OPERATOR_REGEXP.test(key)
921
- ) {
922
- continue;
923
- }
924
- const idx = key.lastIndexOf(".");
925
- if (idx <= 0 || idx >= key.length - 1) {
926
- continue;
927
- }
928
- const nested = key.slice(0, idx);
929
- const final = key.slice(idx + 1);
930
- addToMap(finalByNestedKey, nested, final);
931
- addToMap(nestedByFinalKey, final, nested);
932
- }
933
- };
934
-
935
- walkDefinitionsForKeys(definitions);
936
1251
  walkDefinitionsForValues(definitions, "");
937
1252
 
938
1253
  compilation.valueCacheVersions.set(
@@ -952,3 +1267,9 @@ DefinePlugin.getCompilationHooks = createHooksRegistry(
952
1267
  );
953
1268
 
954
1269
  module.exports = DefinePlugin;
1270
+ module.exports.VALUE_DEP_MAIN = VALUE_DEP_MAIN;
1271
+ module.exports.VALUE_DEP_PREFIX = VALUE_DEP_PREFIX;
1272
+ module.exports.getMergedDefinitionNode = getMergedDefinitionNode;
1273
+ module.exports.getRuntimeRequirements = getRuntimeRequirements;
1274
+ module.exports.stringifyMergedDefinition = stringifyMergedDefinition;
1275
+ module.exports.toPropertyKey = toPropertyKey;
package/lib/Entrypoint.js CHANGED
@@ -11,7 +11,7 @@ const SortableSet = require("./util/SortableSet");
11
11
  /** @typedef {import("../declarations/WebpackOptions").EntryDescriptionNormalized} EntryDescription */
12
12
  /** @typedef {import("./Chunk")} Chunk */
13
13
 
14
- /** @typedef {{ name?: string } & Omit<EntryDescription, "import">} EntryOptions */
14
+ /** @typedef {{ name?: string, worklet?: boolean } & Omit<EntryDescription, "import">} EntryOptions */
15
15
 
16
16
  /**
17
17
  * Entrypoint serves as an encapsulation primitive for chunks that are