webpack 5.106.2 → 5.107.0

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 (220) hide show
  1. package/README.md +2 -2
  2. package/lib/APIPlugin.js +1 -1
  3. package/lib/Cache.js +3 -6
  4. package/lib/CompatibilityPlugin.js +8 -7
  5. package/lib/Compilation.js +34 -26
  6. package/lib/Compiler.js +4 -13
  7. package/lib/ContextModule.js +2 -2
  8. package/lib/DefinePlugin.js +2 -2
  9. package/lib/Dependency.js +22 -1
  10. package/lib/DependencyTemplate.js +2 -1
  11. package/lib/EnvironmentPlugin.js +1 -1
  12. package/lib/EvalSourceMapDevToolPlugin.js +8 -9
  13. package/lib/ExternalModule.js +76 -15
  14. package/lib/ExternalModuleFactoryPlugin.js +5 -0
  15. package/lib/FileSystemInfo.js +187 -72
  16. package/lib/Generator.js +3 -3
  17. package/lib/HotModuleReplacementPlugin.js +26 -8
  18. package/lib/IgnorePlugin.js +2 -1
  19. package/lib/Module.js +19 -18
  20. package/lib/ModuleFactory.js +1 -1
  21. package/lib/ModuleSourceTypeConstants.js +31 -1
  22. package/lib/ModuleTypeConstants.js +12 -3
  23. package/lib/MultiCompiler.js +2 -2
  24. package/lib/NodeStuffPlugin.js +1 -1
  25. package/lib/NormalModule.js +13 -31
  26. package/lib/NormalModuleFactory.js +10 -2
  27. package/lib/Parser.js +1 -1
  28. package/lib/ProgressPlugin.js +129 -56
  29. package/lib/RuntimeGlobals.js +5 -5
  30. package/lib/RuntimeModule.js +9 -7
  31. package/lib/RuntimePlugin.js +11 -0
  32. package/lib/WarnCaseSensitiveModulesPlugin.js +70 -2
  33. package/lib/WarnDeprecatedOptionPlugin.js +1 -1
  34. package/lib/WarnNoModeSetPlugin.js +16 -1
  35. package/lib/Watching.js +2 -3
  36. package/lib/WebpackError.js +3 -77
  37. package/lib/WebpackIsIncludedPlugin.js +1 -1
  38. package/lib/WebpackOptionsApply.js +13 -1
  39. package/lib/asset/AssetBytesGenerator.js +6 -2
  40. package/lib/asset/AssetGenerator.js +22 -8
  41. package/lib/asset/AssetModulesPlugin.js +3 -1
  42. package/lib/asset/AssetSourceGenerator.js +6 -2
  43. package/lib/buildChunkGraph.js +4 -6
  44. package/lib/cache/PackFileCacheStrategy.js +4 -4
  45. package/lib/cli.js +3 -1
  46. package/lib/config/defaults.js +197 -10
  47. package/lib/config/normalization.js +3 -1
  48. package/lib/css/CssGenerator.js +320 -105
  49. package/lib/css/CssInjectStyleRuntimeModule.js +44 -42
  50. package/lib/css/CssLoadingRuntimeModule.js +22 -4
  51. package/lib/{CssModule.js → css/CssModule.js} +15 -15
  52. package/lib/css/CssModulesPlugin.js +166 -86
  53. package/lib/css/CssParser.js +566 -269
  54. package/lib/css/walkCssTokens.js +148 -2
  55. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +1 -1
  56. package/lib/dependencies/CommonJsDependencyHelpers.js +63 -0
  57. package/lib/dependencies/CommonJsExportRequireDependency.js +54 -10
  58. package/lib/dependencies/CommonJsExportsParserPlugin.js +1 -1
  59. package/lib/dependencies/CommonJsFullRequireDependency.js +32 -9
  60. package/lib/dependencies/CommonJsImportsParserPlugin.js +4 -3
  61. package/lib/dependencies/CommonJsRequireDependency.js +67 -4
  62. package/lib/dependencies/ContextDependency.js +1 -1
  63. package/lib/dependencies/ContextDependencyHelpers.js +1 -1
  64. package/lib/dependencies/CreateRequireParserPlugin.js +1 -1
  65. package/lib/dependencies/CriticalDependencyWarning.js +1 -1
  66. package/lib/dependencies/CssIcssExportDependency.js +332 -67
  67. package/lib/dependencies/CssIcssImportDependency.js +49 -7
  68. package/lib/dependencies/CssIcssSymbolDependency.js +11 -3
  69. package/lib/dependencies/CssImportDependency.js +8 -0
  70. package/lib/dependencies/CssUrlDependency.js +25 -0
  71. package/lib/dependencies/HarmonyDetectionParserPlugin.js +1 -1
  72. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +8 -7
  73. package/lib/dependencies/HarmonyExportExpressionDependency.js +22 -14
  74. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +110 -3
  75. package/lib/dependencies/HarmonyImportDependency.js +10 -2
  76. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +22 -1
  77. package/lib/dependencies/HarmonyImportSpecifierDependency.js +1 -1
  78. package/lib/{HarmonyLinkingError.js → dependencies/HarmonyLinkingError.js} +5 -3
  79. package/lib/dependencies/HtmlInlineScriptDependency.js +133 -0
  80. package/lib/dependencies/HtmlInlineStyleDependency.js +101 -0
  81. package/lib/dependencies/HtmlScriptSrcDependency.js +318 -0
  82. package/lib/dependencies/HtmlSourceDependency.js +127 -0
  83. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +1 -1
  84. package/lib/dependencies/ImportParserPlugin.js +2 -2
  85. package/lib/dependencies/ImportPhase.js +1 -1
  86. package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +1 -1
  87. package/lib/{RequireJsStuffPlugin.js → dependencies/RequireJsStuffPlugin.js} +7 -7
  88. package/lib/dependencies/SystemPlugin.js +1 -1
  89. package/lib/dependencies/WebAssemblyImportDependency.js +1 -1
  90. package/lib/dependencies/WorkerPlugin.js +2 -2
  91. package/lib/{DelegatedModule.js → dll/DelegatedModule.js} +31 -31
  92. package/lib/{DelegatedModuleFactoryPlugin.js → dll/DelegatedModuleFactoryPlugin.js} +4 -4
  93. package/lib/{DelegatedPlugin.js → dll/DelegatedPlugin.js} +2 -2
  94. package/lib/{DllEntryPlugin.js → dll/DllEntryPlugin.js} +4 -4
  95. package/lib/{DllModule.js → dll/DllModule.js} +24 -24
  96. package/lib/{DllModuleFactory.js → dll/DllModuleFactory.js} +4 -4
  97. package/lib/{DllPlugin.js → dll/DllPlugin.js} +6 -5
  98. package/lib/{DllReferencePlugin.js → dll/DllReferencePlugin.js} +14 -14
  99. package/lib/{LibManifestPlugin.js → dll/LibManifestPlugin.js} +9 -9
  100. package/lib/{AsyncDependencyToInitialChunkError.js → errors/AsyncDependencyToInitialChunkError.js} +2 -2
  101. package/lib/errors/BuildCycleError.js +1 -1
  102. package/lib/{ChunkRenderError.js → errors/ChunkRenderError.js} +1 -1
  103. package/lib/{CodeGenerationError.js → errors/CodeGenerationError.js} +1 -1
  104. package/lib/{CommentCompilationWarning.js → errors/CommentCompilationWarning.js} +3 -3
  105. package/lib/{ConcurrentCompilationError.js → errors/ConcurrentCompilationError.js} +4 -2
  106. package/lib/{EnvironmentNotSupportAsyncWarning.js → errors/EnvironmentNotSupportAsyncWarning.js} +4 -4
  107. package/lib/{HookWebpackError.js → errors/HookWebpackError.js} +5 -5
  108. package/lib/{IgnoreErrorModuleFactory.js → errors/IgnoreErrorModuleFactory.js} +4 -4
  109. package/lib/{InvalidDependenciesModuleWarning.js → errors/InvalidDependenciesModuleWarning.js} +3 -3
  110. package/lib/errors/JSONParseError.js +114 -0
  111. package/lib/{ModuleBuildError.js → errors/ModuleBuildError.js} +5 -5
  112. package/lib/{ModuleDependencyError.js → errors/ModuleDependencyError.js} +2 -2
  113. package/lib/{ModuleDependencyWarning.js → errors/ModuleDependencyWarning.js} +4 -4
  114. package/lib/{ModuleError.js → errors/ModuleError.js} +5 -5
  115. package/lib/{ModuleHashingError.js → errors/ModuleHashingError.js} +1 -1
  116. package/lib/{ModuleNotFoundError.js → errors/ModuleNotFoundError.js} +2 -2
  117. package/lib/{ModuleParseError.js → errors/ModuleParseError.js} +8 -6
  118. package/lib/{ModuleRestoreError.js → errors/ModuleRestoreError.js} +1 -1
  119. package/lib/{ModuleStoreError.js → errors/ModuleStoreError.js} +1 -1
  120. package/lib/{ModuleWarning.js → errors/ModuleWarning.js} +5 -5
  121. package/lib/{NodeStuffInWebError.js → errors/NodeStuffInWebError.js} +4 -4
  122. package/lib/errors/NonErrorEmittedError.js +28 -0
  123. package/lib/{UnhandledSchemeError.js → errors/UnhandledSchemeError.js} +2 -2
  124. package/lib/{UnsupportedFeatureWarning.js → errors/UnsupportedFeatureWarning.js} +3 -3
  125. package/lib/errors/WebpackError.js +84 -0
  126. package/lib/html/HtmlGenerator.js +379 -0
  127. package/lib/html/HtmlModulesPlugin.js +433 -0
  128. package/lib/html/HtmlParser.js +1489 -0
  129. package/lib/html/walkHtmlTokens.js +2733 -0
  130. package/lib/ids/IdHelpers.js +2 -1
  131. package/lib/index.js +34 -15
  132. package/lib/javascript/JavascriptModulesPlugin.js +89 -8
  133. package/lib/javascript/JavascriptParser.js +197 -16
  134. package/lib/javascript/JavascriptParserHelpers.js +1 -1
  135. package/lib/json/JsonParser.js +7 -16
  136. package/lib/library/AbstractLibraryPlugin.js +1 -1
  137. package/lib/library/EnableLibraryPlugin.js +1 -1
  138. package/lib/{FalseIIFEUmdWarning.js → library/FalseIIFEUmdWarning.js} +1 -1
  139. package/lib/library/ModuleLibraryPlugin.js +74 -0
  140. package/lib/node/NodeEnvironmentPlugin.js +4 -2
  141. package/lib/node/nodeConsole.js +113 -64
  142. package/lib/optimize/ConcatenatedModule.js +51 -6
  143. package/lib/optimize/InnerGraph.js +1 -1
  144. package/lib/optimize/InnerGraphPlugin.js +11 -1
  145. package/lib/optimize/MinMaxSizeWarning.js +4 -4
  146. package/lib/optimize/ModuleConcatenationPlugin.js +15 -7
  147. package/lib/optimize/RealContentHashPlugin.js +89 -26
  148. package/lib/optimize/SideEffectsFlagPlugin.js +111 -3
  149. package/lib/optimize/SplitChunksPlugin.js +1 -1
  150. package/lib/performance/AssetsOverSizeLimitWarning.js +2 -2
  151. package/lib/performance/EntrypointsOverSizeLimitWarning.js +2 -2
  152. package/lib/performance/NoAsyncChunksWarning.js +5 -3
  153. package/lib/performance/SizeLimitsPlugin.js +1 -1
  154. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +4 -1
  155. package/lib/rules/UseEffectRulePlugin.js +4 -3
  156. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +119 -13
  157. package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +35 -0
  158. package/lib/schemes/DataUriPlugin.js +13 -1
  159. package/lib/schemes/VirtualUrlPlugin.js +1 -1
  160. package/lib/serialization/SerializerMiddleware.js +2 -2
  161. package/lib/sharing/ConsumeSharedPlugin.js +2 -2
  162. package/lib/sharing/ConsumeSharedRuntimeModule.js +8 -4
  163. package/lib/sharing/ProvideSharedModule.js +1 -1
  164. package/lib/sharing/ProvideSharedPlugin.js +1 -1
  165. package/lib/sharing/resolveMatchedConfigs.js +1 -1
  166. package/lib/stats/DefaultStatsFactoryPlugin.js +2 -2
  167. package/lib/stats/DefaultStatsPresetPlugin.js +1 -1
  168. package/lib/stats/DefaultStatsPrinterPlugin.js +1 -1
  169. package/lib/stats/StatsFactory.js +1 -1
  170. package/lib/typescript/TypeScriptPlugin.js +210 -0
  171. package/lib/url/URLParserPlugin.js +2 -2
  172. package/lib/util/AsyncQueue.js +2 -2
  173. package/lib/util/Hash.js +2 -2
  174. package/lib/util/LocConverter.js +53 -0
  175. package/lib/util/SortableSet.js +1 -1
  176. package/lib/util/cleverMerge.js +2 -2
  177. package/lib/util/comparators.js +3 -3
  178. package/lib/util/concatenate.js +3 -3
  179. package/lib/util/conventions.js +42 -1
  180. package/lib/util/createMappings.js +118 -0
  181. package/lib/{formatLocation.js → util/formatLocation.js} +2 -2
  182. package/lib/{SizeFormatHelpers.js → util/formatSize.js} +3 -1
  183. package/lib/util/fs.js +8 -8
  184. package/lib/util/hash/md4.js +1 -1
  185. package/lib/util/hash/xxhash64.js +1 -1
  186. package/lib/util/identifier.js +48 -0
  187. package/lib/util/internalSerializables.js +35 -19
  188. package/lib/util/magicComment.js +10 -7
  189. package/lib/util/parseJson.js +2 -73
  190. package/lib/util/source.js +21 -0
  191. package/lib/util/topologicalSort.js +69 -0
  192. package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +2 -2
  193. package/lib/wasm-async/AsyncWebAssemblyParser.js +1 -1
  194. package/lib/wasm-sync/UnsupportedWebAssemblyFeatureError.js +5 -3
  195. package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +1 -1
  196. package/lib/wasm-sync/WebAssemblyInInitialChunkError.js +5 -3
  197. package/lib/webpack.js +3 -1
  198. package/package.json +22 -20
  199. package/schemas/WebpackOptions.check.js +1 -1
  200. package/schemas/WebpackOptions.json +118 -3
  201. package/schemas/plugins/{DllPlugin.check.d.ts → HtmlGeneratorOptions.check.d.ts} +1 -1
  202. package/schemas/plugins/HtmlGeneratorOptions.check.js +6 -0
  203. package/schemas/plugins/HtmlGeneratorOptions.json +3 -0
  204. package/schemas/plugins/ProgressPlugin.check.js +1 -1
  205. package/schemas/plugins/ProgressPlugin.json +22 -0
  206. package/schemas/plugins/{DllReferencePlugin.check.d.ts → css/CssAutoOrModuleParserOptions.check.d.ts} +1 -1
  207. package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +6 -0
  208. package/schemas/plugins/css/CssAutoOrModuleParserOptions.json +3 -0
  209. package/schemas/plugins/dll/DllPlugin.check.d.ts +7 -0
  210. package/schemas/plugins/dll/DllReferencePlugin.check.d.ts +7 -0
  211. package/types.d.ts +810 -101
  212. package/lib/CaseSensitiveModulesWarning.js +0 -80
  213. package/lib/GraphHelpers.js +0 -49
  214. package/lib/NoModeWarning.js +0 -23
  215. package/lib/css/CssMergeStyleSheetsRuntimeModule.js +0 -57
  216. /package/lib/{AbstractMethodError.js → errors/AbstractMethodError.js} +0 -0
  217. /package/schemas/plugins/{DllPlugin.check.js → dll/DllPlugin.check.js} +0 -0
  218. /package/schemas/plugins/{DllPlugin.json → dll/DllPlugin.json} +0 -0
  219. /package/schemas/plugins/{DllReferencePlugin.check.js → dll/DllReferencePlugin.check.js} +0 -0
  220. /package/schemas/plugins/{DllReferencePlugin.json → dll/DllReferencePlugin.json} +0 -0
@@ -8,7 +8,7 @@
8
8
  const { SyncBailHook } = require("tapable");
9
9
  const { CachedSource, CompatSource, RawSource } = require("webpack-sources");
10
10
  const Compilation = require("../Compilation");
11
- const WebpackError = require("../WebpackError");
11
+ const WebpackError = require("../errors/WebpackError");
12
12
  const { compareSelect, compareStrings } = require("../util/comparators");
13
13
  const createHash = require("../util/createHash");
14
14
 
@@ -46,24 +46,77 @@ const addToList = (itemOrItems, list) => {
46
46
  };
47
47
 
48
48
  /**
49
- * Map and deduplicate buffers.
49
+ * Compares two non-empty buffer chunk arrays for byte-equality without
50
+ * allocating a concatenated buffer.
51
+ * @param {Buffer[]} a first chunk array
52
+ * @param {Buffer[]} b second chunk array
53
+ * @returns {boolean} true if the concatenations are byte-equal
54
+ */
55
+ const bufferArraysEqual = (a, b) => {
56
+ let aIdx = 0;
57
+ let aOff = 0;
58
+ let bIdx = 0;
59
+ let bOff = 0;
60
+ while (aIdx < a.length && bIdx < b.length) {
61
+ const aBuf = a[aIdx];
62
+ const bBuf = b[bIdx];
63
+ const len = Math.min(aBuf.length - aOff, bBuf.length - bOff);
64
+ if (aBuf.compare(bBuf, bOff, bOff + len, aOff, aOff + len) !== 0) {
65
+ return false;
66
+ }
67
+ aOff += len;
68
+ bOff += len;
69
+ if (aOff === aBuf.length) {
70
+ aIdx++;
71
+ aOff = 0;
72
+ }
73
+ if (bOff === bBuf.length) {
74
+ bIdx++;
75
+ bOff = 0;
76
+ }
77
+ }
78
+ return aIdx === a.length && bIdx === b.length;
79
+ };
80
+
81
+ /**
82
+ * Map sources to their buffer chunks and deduplicate by total byte content,
83
+ * grouping by total length first to avoid full comparisons.
50
84
  * @template T
51
85
  * @param {T[]} input list
52
- * @param {(item: T) => Buffer} fn map function
53
- * @returns {Buffer[]} buffers without duplicates
86
+ * @param {(item: T) => Source} fn map function returning a Source
87
+ * @returns {Buffer[][]} unique chunk arrays
54
88
  */
55
- const mapAndDeduplicateBuffers = (input, fn) => {
56
- // Buffer.equals compares size first so this should be efficient enough
57
- // If it becomes a performance problem we can use a map and group by size
58
- // instead of looping over all assets.
59
- /** @type {Buffer[]} */
89
+ const mapAndDeduplicateSourceBuffers = (input, fn) => {
90
+ /** @type {Map<number, Buffer[][]>} */
91
+ const bySize = new Map();
92
+ /** @type {Buffer[][]} */
60
93
  const result = [];
61
- outer: for (const value of input) {
62
- const buf = fn(value);
63
- for (const other of result) {
64
- if (buf.equals(other)) continue outer;
94
+ for (const value of input) {
95
+ const source = fn(value);
96
+ // TODO webpack 6: drop the `buffers` check, require webpack-sources >= 3.4
97
+ // and call `source.buffers()` unconditionally.
98
+ const chunks =
99
+ // TODO remove in webpack 6, this is protection against authors who directly use `webpack-sources` outdated version
100
+ typeof source.buffers === "function"
101
+ ? source.buffers()
102
+ : [source.buffer()];
103
+ let total = 0;
104
+ for (const c of chunks) total += c.length;
105
+ const sameSize = bySize.get(total);
106
+ if (sameSize) {
107
+ let duplicate = false;
108
+ for (const other of sameSize) {
109
+ if (bufferArraysEqual(chunks, other)) {
110
+ duplicate = true;
111
+ break;
112
+ }
113
+ }
114
+ if (duplicate) continue;
115
+ sameSize.push(chunks);
116
+ } else {
117
+ bySize.set(total, [chunks]);
65
118
  }
66
- result.push(buf);
119
+ result.push(chunks);
67
120
  }
68
121
  return result;
69
122
  };
@@ -437,24 +490,34 @@ ${referencingAssets
437
490
  : computeNewContent(asset)
438
491
  )
439
492
  );
440
- const assetsContent = mapAndDeduplicateBuffers(assets, (asset) => {
441
- if (/** @type {Hashes} */ (asset.ownHashes).has(oldHash)) {
442
- return asset.newSourceWithoutOwn
443
- ? asset.newSourceWithoutOwn.buffer()
444
- : asset.source.buffer();
493
+ const uniqueChunkArrays = mapAndDeduplicateSourceBuffers(
494
+ assets,
495
+ (asset) => {
496
+ if (/** @type {Hashes} */ (asset.ownHashes).has(oldHash)) {
497
+ return asset.newSourceWithoutOwn || asset.source;
498
+ }
499
+ return asset.newSource || asset.source;
445
500
  }
446
- return asset.newSource
447
- ? asset.newSource.buffer()
448
- : asset.source.buffer();
449
- });
450
- let newHash = hooks.updateHash.call(assetsContent, oldHash);
501
+ );
502
+ /** @type {string | undefined} */
503
+ let newHash;
504
+ // Only materialize the public `Buffer[]` (one entry per unique
505
+ // asset) when something is tapped; otherwise the hot path feeds
506
+ // chunks into the hash directly, avoiding per-asset Buffer.concat.
507
+ if (hooks.updateHash.isUsed()) {
508
+ const assetsContent = uniqueChunkArrays.map((chunks) =>
509
+ chunks.length === 1 ? chunks[0] : Buffer.concat(chunks)
510
+ );
511
+ newHash =
512
+ hooks.updateHash.call(assetsContent, oldHash) || undefined;
513
+ }
451
514
  if (!newHash) {
452
515
  const hash = createHash(this._hashFunction);
453
516
  if (compilation.outputOptions.hashSalt) {
454
517
  hash.update(compilation.outputOptions.hashSalt);
455
518
  }
456
- for (const content of assetsContent) {
457
- hash.update(content);
519
+ for (const chunks of uniqueChunkArrays) {
520
+ for (const c of chunks) hash.update(c);
458
521
  }
459
522
  const digest = hash.digest(this._hashDigest);
460
523
  newHash = digest.slice(0, oldHash.length);
@@ -14,12 +14,14 @@ const {
14
14
  const { STAGE_DEFAULT } = require("../OptimizationStages");
15
15
  const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency");
16
16
  const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency");
17
- const formatLocation = require("../formatLocation");
17
+ const formatLocation = require("../util/formatLocation");
18
+ const { CompilerHintNotationRegExp } = require("../util/magicComment");
18
19
 
19
20
  /** @typedef {import("estree").MaybeNamedClassDeclaration} MaybeNamedClassDeclaration */
20
21
  /** @typedef {import("estree").MaybeNamedFunctionDeclaration} MaybeNamedFunctionDeclaration */
21
22
  /** @typedef {import("estree").ModuleDeclaration} ModuleDeclaration */
22
23
  /** @typedef {import("estree").Statement} Statement */
24
+ /** @typedef {import("estree").CallExpression} CallExpression */
23
25
  /** @typedef {import("../Compiler")} Compiler */
24
26
  /** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
25
27
  /** @typedef {import("../Module")} Module */
@@ -63,6 +65,24 @@ const globToRegexp = (glob, cache) => {
63
65
  return regexp;
64
66
  };
65
67
 
68
+ /**
69
+ * @param {JavascriptParser} parser parser
70
+ * @param {number} start start position
71
+ * @param {number} end end position
72
+ * @returns {boolean} if annotation is found in the range
73
+ */
74
+ const hasNoSideEffectsNotation = (parser, start, end) => {
75
+ // Fast path
76
+ if (end - start < 18) return false;
77
+
78
+ const comments = parser.getComments([start, end]);
79
+ return comments.some(
80
+ (c) =>
81
+ c.type === "Block" &&
82
+ CompilerHintNotationRegExp.NoSideEffects.test(c.value)
83
+ );
84
+ };
85
+
66
86
  const PLUGIN_NAME = "SideEffectsFlagPlugin";
67
87
 
68
88
  class SideEffectsFlagPlugin {
@@ -129,7 +149,7 @@ class SideEffectsFlagPlugin {
129
149
  * @param {JavascriptParser} parser the parser
130
150
  * @returns {void}
131
151
  */
132
- const parserHandler = (parser) => {
152
+ const applySideEffectsStmtHandler = (parser) => {
133
153
  /** @type {undefined | Statement | ModuleDeclaration | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration} */
134
154
  let sideEffectsStatement;
135
155
  parser.hooks.program.tap(PLUGIN_NAME, () => {
@@ -260,6 +280,91 @@ class SideEffectsFlagPlugin {
260
280
  }
261
281
  });
262
282
  };
283
+
284
+ /**
285
+ * @param {JavascriptParser} parser the parser
286
+ * @returns {void}
287
+ */
288
+ const applyNoSideEffectsNotationHandler = (parser) => {
289
+ /** @type {Set<string>} */
290
+ let noSideEffectsFnNames;
291
+
292
+ parser.hooks.program.tap(PLUGIN_NAME, () => {
293
+ noSideEffectsFnNames = new Set();
294
+ });
295
+
296
+ // Detect on function declarations
297
+ // Covers:
298
+ // 1. function foo
299
+ // 2. export function foo
300
+ // 3. export default function foo
301
+ parser.hooks.preStatement.tap(PLUGIN_NAME, (statement) => {
302
+ if (parser.scope.topLevelScope !== true) return;
303
+ if (statement.type !== "FunctionDeclaration" || !statement.id) {
304
+ return;
305
+ }
306
+ const commentsStart = parser.prevStatement
307
+ ? /** @type {Range} */ (parser.prevStatement.range)[1]
308
+ : 0;
309
+ if (
310
+ hasNoSideEffectsNotation(
311
+ parser,
312
+ commentsStart,
313
+ /** @type {Range} */ (statement.range)[0]
314
+ )
315
+ ) {
316
+ noSideEffectsFnNames.add(statement.id.name);
317
+ }
318
+ });
319
+
320
+ // Detect on variable declarations with function init
321
+ parser.hooks.preDeclarator.tap(PLUGIN_NAME, (decl, statement) => {
322
+ if (parser.scope.topLevelScope !== true) return;
323
+ if (!decl.init || decl.id.type !== "Identifier") return;
324
+ if (!decl.init.type.endsWith("FunctionExpression")) return;
325
+
326
+ let hasAnnotation = false;
327
+ // Before the VariableDeclaration (only for const)
328
+ if (statement.kind === "const") {
329
+ const commentsStart = parser.prevStatement
330
+ ? /** @type {Range} */ (parser.prevStatement.range)[1]
331
+ : 0;
332
+ hasAnnotation = hasNoSideEffectsNotation(
333
+ parser,
334
+ commentsStart,
335
+ /** @type {Range} */ (statement.range)[0]
336
+ );
337
+ }
338
+
339
+ if (!hasAnnotation) {
340
+ hasAnnotation = hasNoSideEffectsNotation(
341
+ parser,
342
+ /** @type {Range} */ (decl.id.range)[1],
343
+ /** @type {Range} */ (decl.init.range)[0]
344
+ );
345
+ }
346
+ if (hasAnnotation) {
347
+ noSideEffectsFnNames.add(decl.id.name);
348
+ }
349
+ });
350
+
351
+ // Mark calls to annotated functions as pure
352
+ parser.hooks.isPure
353
+ .for("CallExpression")
354
+ .tap(PLUGIN_NAME, (expression, commentsStartPos) => {
355
+ const expr = /** @type {CallExpression} */ (expression);
356
+ if (expr.callee.type !== "Identifier") return;
357
+ if (!noSideEffectsFnNames.has(expr.callee.name)) return;
358
+ commentsStartPos = /** @type {Range} */ (expr.callee.range)[1];
359
+ for (const arg of expr.arguments) {
360
+ if (arg.type === "SpreadElement") return;
361
+ if (!parser.isPure(arg, commentsStartPos)) return;
362
+ commentsStartPos = /** @type {Range} */ (arg.range)[1];
363
+ }
364
+ return true;
365
+ });
366
+ };
367
+
263
368
  for (const key of [
264
369
  JAVASCRIPT_MODULE_TYPE_AUTO,
265
370
  JAVASCRIPT_MODULE_TYPE_ESM,
@@ -267,7 +372,10 @@ class SideEffectsFlagPlugin {
267
372
  ]) {
268
373
  normalModuleFactory.hooks.parser
269
374
  .for(key)
270
- .tap(PLUGIN_NAME, parserHandler);
375
+ .tap(PLUGIN_NAME, (parser) => {
376
+ applyNoSideEffectsNotationHandler(parser);
377
+ applySideEffectsStmtHandler(parser);
378
+ });
271
379
  }
272
380
  }
273
381
  compilation.hooks.optimizeDependencies.tap(
@@ -7,7 +7,7 @@
7
7
 
8
8
  const Chunk = require("../Chunk");
9
9
  const { STAGE_ADVANCED } = require("../OptimizationStages");
10
- const WebpackError = require("../WebpackError");
10
+ const WebpackError = require("../errors/WebpackError");
11
11
  const { requestToId } = require("../ids/IdHelpers");
12
12
  const { isSubset } = require("../util/SetHelpers");
13
13
  const SortableSet = require("../util/SortableSet");
@@ -5,8 +5,8 @@
5
5
 
6
6
  "use strict";
7
7
 
8
- const { formatSize } = require("../SizeFormatHelpers");
9
- const WebpackError = require("../WebpackError");
8
+ const WebpackError = require("../errors/WebpackError");
9
+ const formatSize = require("../util/formatSize");
10
10
 
11
11
  /** @typedef {import("./SizeLimitsPlugin").AssetDetails} AssetDetails */
12
12
 
@@ -5,8 +5,8 @@
5
5
 
6
6
  "use strict";
7
7
 
8
- const { formatSize } = require("../SizeFormatHelpers");
9
- const WebpackError = require("../WebpackError");
8
+ const WebpackError = require("../errors/WebpackError");
9
+ const formatSize = require("../util/formatSize");
10
10
 
11
11
  /** @typedef {import("./SizeLimitsPlugin").EntrypointDetails} EntrypointDetails */
12
12
 
@@ -5,9 +5,9 @@
5
5
 
6
6
  "use strict";
7
7
 
8
- const WebpackError = require("../WebpackError");
8
+ const WebpackError = require("../errors/WebpackError");
9
9
 
10
- module.exports = class NoAsyncChunksWarning extends WebpackError {
10
+ class NoAsyncChunksWarning extends WebpackError {
11
11
  constructor() {
12
12
  super(
13
13
  "webpack performance recommendations: \n" +
@@ -18,4 +18,6 @@ module.exports = class NoAsyncChunksWarning extends WebpackError {
18
18
  /** @type {string} */
19
19
  this.name = "NoAsyncChunksWarning";
20
20
  }
21
- };
21
+ }
22
+
23
+ module.exports = NoAsyncChunksWarning;
@@ -16,7 +16,7 @@ const NoAsyncChunksWarning = require("./NoAsyncChunksWarning");
16
16
  /** @typedef {import("../Compilation").Asset} Asset */
17
17
  /** @typedef {import("../Compiler")} Compiler */
18
18
  /** @typedef {import("../Entrypoint")} Entrypoint */
19
- /** @typedef {import("../WebpackError")} WebpackError */
19
+ /** @typedef {import("../errors/WebpackError")} WebpackError */
20
20
 
21
21
  /**
22
22
  * Defines the asset details type used by this module.
@@ -39,10 +39,13 @@ class ChunkPrefetchTriggerRuntimeModule extends RuntimeModule {
39
39
  `${
40
40
  RuntimeGlobals.ensureChunkHandlers
41
41
  }.prefetch = ${runtimeTemplate.expressionFunction(
42
+ // Prefetch is best-effort; silence rejections so a failed chunk
43
+ // load (e.g. chunkLoadTimeout) doesn't surface as an unhandled
44
+ // rejection through this dangling Promise.all chain.
42
45
  `Promise.all(promises).then(${runtimeTemplate.basicFunction(
43
46
  "",
44
47
  body
45
- )})`,
48
+ )}, ${runtimeTemplate.basicFunction("", "")})`,
46
49
  "chunkId, promises"
47
50
  )};`
48
51
  ])
@@ -13,6 +13,7 @@ const util = require("util");
13
13
  /** @typedef {import("../../declarations/WebpackOptions").RuleSetRule} RuleSetRule */
14
14
  /** @typedef {import("../../declarations/WebpackOptions").RuleSetUse} RuleSetUse */
15
15
  /** @typedef {import("../../declarations/WebpackOptions").RuleSetUseItem} RuleSetUseItem */
16
+ /** @typedef {import("../../declarations/WebpackOptions").RuleSetUseFunction} RuleSetUseFunction */
16
17
  /** @typedef {import("./RuleSetCompiler")} RuleSetCompiler */
17
18
  /** @typedef {import("./RuleSetCompiler").Effect} Effect */
18
19
  /** @typedef {import("./RuleSetCompiler").EffectData} EffectData */
@@ -82,7 +83,7 @@ class UseEffectRulePlugin {
82
83
  * Returns effect.
83
84
  * @param {string} path options path
84
85
  * @param {string} defaultIdent default ident when none is provided
85
- * @param {Exclude<NonNullable<RuleSetUseItem>, EXPECTED_FUNCTION>} item user provided use value
86
+ * @param {Exclude<NonNullable<RuleSetUseItem>, RuleSetUseFunction>} item user provided use value
86
87
  * @returns {Effect} effect
87
88
  */
88
89
  const useToEffectRaw = (path, defaultIdent, item) => {
@@ -132,7 +133,7 @@ class UseEffectRulePlugin {
132
133
  useToEffectRaw(
133
134
  `${path}[${idx}]`,
134
135
  "[[missing ident]]",
135
- /** @type {Exclude<RuleSetUseItem, EXPECTED_FUNCTION>} */
136
+ /** @type {Exclude<RuleSetUseItem, RuleSetUseFunction>} */
136
137
  (item)
137
138
  )
138
139
  );
@@ -141,7 +142,7 @@ class UseEffectRulePlugin {
141
142
  useToEffectRaw(
142
143
  path,
143
144
  "[[missing ident]]",
144
- /** @type {Exclude<RuleSetUseItem, EXPECTED_FUNCTION>} */
145
+ /** @type {Exclude<RuleSetUseItem, RuleSetUseFunction>} */
145
146
  (items)
146
147
  )
147
148
  ];
@@ -121,15 +121,40 @@ class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
121
121
  ? "init?.();"
122
122
  : "if (init) init();";
123
123
  return `${fn} = ${runtimeTemplate.basicFunction("moduleId, mode", [
124
+ // Per the TC39 import-defer spec, deferred namespaces are
125
+ // distinct from their eager counterparts and the same module
126
+ // referenced from multiple defer-import sites must yield the
127
+ // same object. Cache the Proxy / fake namespace per-moduleId so
128
+ // repeated calls (including across files) share identity.
129
+ //
130
+ // Bit 16 (`createFakeNamespaceObject`'s "return value when
131
+ // it's Promise-like" flag added by
132
+ // `RuntimeTemplate.moduleNamespacePromise` for dynamic
133
+ // imports) is irrelevant for deferred namespaces — the value
134
+ // passed into `createFakeNamespaceObject` here is always the
135
+ // resolved module exports (after unwrapping the async-module
136
+ // export symbol when present), never a Promise. Strip it
137
+ // once so all downstream behavior, the cache key, and the
138
+ // `createFakeNamespaceObject` call below see the same shape
139
+ // mode. This keeps static defer (mode 8) and dynamic
140
+ // `await import.defer` (mode 8 | 16) sharing the same
141
+ // Deferred Module Namespace object, while still keying by
142
+ // `(moduleId, mode)` so distinct exports-type shapes
143
+ // (e.g. one importer treats a CJS module as
144
+ // "default-with-named", another as "namespace") get
145
+ // distinct cache entries.
146
+ "mode &= ~16;",
147
+ "var byMode = __webpack_module_deferred_namespace_cache__[moduleId];",
148
+ "if (byMode && byMode[mode] !== undefined) return byMode[mode];",
149
+ "if (!byMode) byMode = __webpack_module_deferred_namespace_cache__[moduleId] = {};",
124
150
  "var cachedModule = __webpack_module_cache__[moduleId];",
125
- "if (cachedModule && cachedModule.error === undefined) {",
151
+ "if (cachedModule && cachedModule.error === undefined && !(mode & 8)) {",
126
152
  Template.indent([
127
153
  "var exports = cachedModule.exports;",
128
154
  hasAsync
129
155
  ? `if (${RuntimeGlobals.asyncModuleExportSymbol} in exports) exports = exports[${RuntimeGlobals.asyncModuleExportSymbol}];`
130
156
  : "",
131
- "if (mode & 8) return exports;",
132
- `return ${RuntimeGlobals.createFakeNamespaceObject}(exports, mode);`
157
+ `return byMode[mode] = ${RuntimeGlobals.createFakeNamespaceObject}(exports, mode);`
133
158
  ]),
134
159
  "}",
135
160
  "",
@@ -141,9 +166,23 @@ class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
141
166
  "init = null;",
142
167
  "if (mode & 8 || mode & 4 && ns.__esModule && typeof ns === 'object') {",
143
168
  Template.indent([
144
- "delete handler.defineProperty;",
145
- "delete handler.deleteProperty;",
146
- "delete handler.set;",
169
+ // Drop only the read-side traps after init: with the
170
+ // resolved namespace's own keys mirrored onto
171
+ // `ns_target` below, the default `Reflect` behavior
172
+ // returns the right values via the live-binding
173
+ // getters, so we no longer need to intercept `get` /
174
+ // `has` / `ownKeys` / `getOwnPropertyDescriptor`.
175
+ //
176
+ // The mutation traps (`set`, `deleteProperty`,
177
+ // `defineProperty`) are kept because per the TC39
178
+ // import-defer spec, `[[Set]]` / `[[Delete]]` /
179
+ // `[[DefineOwnProperty]]` on a Deferred Module
180
+ // Namespace Exotic Object never succeed — and the
181
+ // proxy target itself remains extensible
182
+ // (architecturally we cannot freeze it up-front),
183
+ // so without these traps `ns.notExported = "x"`
184
+ // after evaluation would silently create a property
185
+ // on the target instead of returning false.
147
186
  "delete handler.get;",
148
187
  "delete handler.has;",
149
188
  "delete handler.ownKeys;",
@@ -153,13 +192,58 @@ class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
153
192
  Template.indent([
154
193
  `ns = ${RuntimeGlobals.createFakeNamespaceObject}(ns, mode);`
155
194
  ]),
195
+ "}",
196
+ // Mirror own properties from the resolved namespace onto the proxy
197
+ // target so that proxy invariants hold for callers that structurally
198
+ // introspect via `Object.keys` / `Object.getOwnPropertyNames` /
199
+ // `Object.getOwnPropertyDescriptor`: when our trap reports a
200
+ // non-configurable descriptor for a key, the target must also have
201
+ // that key with a matching descriptor.
202
+ //
203
+ // `__esModule` and `Symbol.toStringTag` are intentionally skipped:
204
+ // the proxy synthesizes "Deferred Module" / true regardless of what
205
+ // the underlying namespace exposes (per the TC39 import-defer
206
+ // proposal, the [[StringTag]] of a Deferred Module Namespace
207
+ // Exotic Object is "Deferred Module"), and the target was already
208
+ // pre-populated with those values below.
209
+ "var keys = Reflect.ownKeys(ns);",
210
+ "for (var i = 0; i < keys.length; i++) {",
211
+ Template.indent([
212
+ "var k = keys[i];",
213
+ 'if (k === "__esModule" || k === Symbol.toStringTag) continue;',
214
+ "if (!Object.prototype.hasOwnProperty.call(ns_target, k)) {",
215
+ Template.indent([
216
+ "try { Object.defineProperty(ns_target, k, Reflect.getOwnPropertyDescriptor(ns, k)); } catch (_) {}"
217
+ ]),
218
+ "}"
219
+ ]),
156
220
  "}"
157
221
  ])};`,
158
222
  "",
159
- "var ns = __webpack_module_deferred_exports__[moduleId] || (__webpack_module_deferred_exports__[moduleId] = { __proto__: null });",
223
+ // The proxy target is a fresh placeholder, separate from
224
+ // `__webpack_module_deferred_exports__[moduleId]` (which is reused
225
+ // by `__webpack_require__` as `module.exports` for deferred-loaded
226
+ // modules and would conflict with our pre-populated synthetic
227
+ // `__esModule` / `Symbol.toStringTag` non-configurable properties).
228
+ // Using a dedicated target keeps the proxy invariant-compliant
229
+ // without interfering with the module's own exports object.
230
+ "var ns_target = { __proto__: null };",
231
+ // Pre-populate the synthetic deferred-namespace properties with
232
+ // fully non-configurable, non-writable, non-enumerable descriptors
233
+ // (matching the TC39 import-defer spec for Module Namespace
234
+ // Exotic Objects). The trap returns the same descriptors below.
235
+ 'Object.defineProperty(ns_target, "__esModule", { value: true });',
236
+ 'Object.defineProperty(ns_target, Symbol.toStringTag, { value: "Deferred Module" });',
237
+ "var ns = ns_target;",
160
238
  "var handler = {",
161
239
  Template.indent([
162
240
  "__proto__: null,",
241
+ // Per the TC39 import-defer proposal, `IsSymbolLikeNamespaceKey`
242
+ // returns true for any Symbol-keyed access (and for "then"); such
243
+ // accesses go through `OrdinaryGetOwnProperty` and must not
244
+ // trigger evaluation of the deferred module. The Symbol checks
245
+ // below short-circuit to the pre-populated target without
246
+ // running `init()`.
163
247
  `get: ${runtimeTemplate.basicFunction("_, name", [
164
248
  "switch (name) {",
165
249
  Template.indent([
@@ -168,6 +252,7 @@ class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
168
252
  'case "then": return undefined;'
169
253
  ]),
170
254
  "}",
255
+ 'if (typeof name === "symbol") return ns_target[name];',
171
256
  init,
172
257
  "return ns[name];"
173
258
  ])},`,
@@ -186,6 +271,7 @@ class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
186
271
  ].filter(Boolean)
187
272
  ),
188
273
  "}",
274
+ 'if (typeof name === "symbol") return name in ns_target;',
189
275
  init,
190
276
  "return name in ns;"
191
277
  ])},`,
@@ -197,11 +283,16 @@ class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
197
283
  `getOwnPropertyDescriptor: ${runtimeTemplate.basicFunction("_, name", [
198
284
  "switch (name) {",
199
285
  Template.indent([
200
- 'case "__esModule": return { value: true, configurable: !(mode & 8) };',
201
- 'case Symbol.toStringTag: return { value: "Deferred Module", configurable: !(mode & 8) };',
286
+ // Match the descriptors actually defined on `ns_target`
287
+ // (non-configurable, non-writable, non-enumerable) so the
288
+ // proxy invariant holds for both the trap result and any
289
+ // post-init forwarding via the deleted-handler path.
290
+ 'case "__esModule": return { value: true, writable: false, enumerable: false, configurable: false };',
291
+ 'case Symbol.toStringTag: return { value: "Deferred Module", writable: false, enumerable: false, configurable: false };',
202
292
  'case "then": return undefined;'
203
293
  ]),
204
294
  "}",
295
+ 'if (typeof name === "symbol") return Reflect.getOwnPropertyDescriptor(ns_target, name);',
205
296
  init,
206
297
  "var desc = Reflect.getOwnPropertyDescriptor(ns, name);",
207
298
  'if (mode & 2 && name == "default" && !desc) {',
@@ -209,18 +300,33 @@ class MakeDeferredNamespaceObjectRuntimeModule extends HelperRuntimeModule {
209
300
  "}",
210
301
  "return desc;"
211
302
  ])},`,
303
+ // `defineProperty` always rejects, but per the TC39 spec it
304
+ // must still trigger evaluation for string keys (the spec
305
+ // algorithm calls `[[GetOwnProperty]]` first, which forces
306
+ // evaluation on a deferred namespace). Symbol keys go through
307
+ // OrdinaryDefineOwnProperty and do not trigger eval.
212
308
  `defineProperty: ${runtimeTemplate.basicFunction("_, name", [
309
+ 'if (typeof name === "symbol" || name === "then") return false;',
310
+ init,
311
+ "return false;"
312
+ ])},`,
313
+ // `deleteProperty` rejects, but per the TC39 spec it must
314
+ // still trigger evaluation for string keys (the spec
315
+ // algorithm calls `GetModuleExportsList` for non-symbol-like
316
+ // keys, forcing evaluation on a deferred namespace).
317
+ `deleteProperty: ${runtimeTemplate.basicFunction("_, name", [
318
+ 'if (typeof name === "symbol" || name === "then") return false;',
213
319
  init,
214
- // Note: This behavior does not match the spec one, but since webpack does not do it either
215
- // for a normal Module Namespace object (in MakeNamespaceObjectRuntimeModule), let's keep it simple.
216
320
  "return false;"
217
321
  ])},`,
218
- `deleteProperty: ${runtimeTemplate.returningFunction("false")},`,
322
+ // `set` always returns false without triggering evaluation —
323
+ // the spec [[Set]] algorithm for Module Namespaces is just
324
+ // "return false" (no [[GetOwnProperty]], no eval).
219
325
  `set: ${runtimeTemplate.returningFunction("false")},`
220
326
  ]),
221
327
  "}",
222
328
  // we don't fully emulate ES Module semantics in this Proxy to align with normal webpack esm namespace object.
223
- "return new Proxy(ns, handler);"
329
+ "return byMode[mode] = new Proxy(ns_target, handler);"
224
330
  ])};`;
225
331
  }
226
332
  }
@@ -0,0 +1,35 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ */
4
+
5
+ "use strict";
6
+
7
+ const RuntimeGlobals = require("../RuntimeGlobals");
8
+ const Template = require("../Template");
9
+ const HelperRuntimeModule = require("./HelperRuntimeModule");
10
+
11
+ /** @typedef {import("../Compilation")} Compilation */
12
+
13
+ class SetAnonymousDefaultNameRuntimeModule extends HelperRuntimeModule {
14
+ constructor() {
15
+ super("set anonymous default export name");
16
+ }
17
+
18
+ /**
19
+ * Generates runtime code for this runtime module.
20
+ * @returns {string | null} runtime code
21
+ */
22
+ generate() {
23
+ const compilation = /** @type {Compilation} */ (this.compilation);
24
+ const { runtimeTemplate } = compilation;
25
+ const fn = RuntimeGlobals.setAnonymousDefaultName;
26
+ return Template.asString([
27
+ "// set .name for anonymous default exports per ES spec",
28
+ `${fn} = ${runtimeTemplate.basicFunction("x", [
29
+ '(Object.getOwnPropertyDescriptor(x, "name") || {}).writable || Object.defineProperty(x, "name", { value: "default", configurable: true });'
30
+ ])};`
31
+ ]);
32
+ }
33
+ }
34
+
35
+ module.exports = SetAnonymousDefaultNameRuntimeModule;