webpack 5.106.2 → 5.107.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 (235) hide show
  1. package/README.md +2 -2
  2. package/lib/APIPlugin.js +1 -1
  3. package/lib/BannerPlugin.js +3 -4
  4. package/lib/Cache.js +3 -6
  5. package/lib/Chunk.js +21 -25
  6. package/lib/ChunkGroup.js +57 -15
  7. package/lib/CompatibilityPlugin.js +8 -7
  8. package/lib/Compilation.js +67 -37
  9. package/lib/Compiler.js +4 -13
  10. package/lib/ContextModule.js +2 -2
  11. package/lib/DefinePlugin.js +2 -2
  12. package/lib/Dependency.js +22 -1
  13. package/lib/DependencyTemplate.js +2 -1
  14. package/lib/EnvironmentPlugin.js +1 -1
  15. package/lib/EvalSourceMapDevToolPlugin.js +8 -10
  16. package/lib/ExportsInfo.js +30 -34
  17. package/lib/ExternalModule.js +91 -26
  18. package/lib/ExternalModuleFactoryPlugin.js +7 -1
  19. package/lib/FileSystemInfo.js +187 -72
  20. package/lib/Generator.js +3 -3
  21. package/lib/HotModuleReplacementPlugin.js +26 -8
  22. package/lib/IgnorePlugin.js +2 -1
  23. package/lib/Module.js +20 -19
  24. package/lib/ModuleFactory.js +1 -1
  25. package/lib/ModuleNotFoundError.js +3 -84
  26. package/lib/ModuleSourceTypeConstants.js +51 -19
  27. package/lib/ModuleTypeConstants.js +12 -3
  28. package/lib/MultiCompiler.js +2 -2
  29. package/lib/NodeStuffPlugin.js +1 -1
  30. package/lib/NormalModule.js +119 -77
  31. package/lib/NormalModuleFactory.js +47 -27
  32. package/lib/Parser.js +1 -1
  33. package/lib/ProgressPlugin.js +129 -56
  34. package/lib/RuntimeGlobals.js +5 -5
  35. package/lib/RuntimeModule.js +9 -7
  36. package/lib/RuntimePlugin.js +12 -1
  37. package/lib/SourceMapDevToolPlugin.js +250 -49
  38. package/lib/Template.js +1 -1
  39. package/lib/TemplatedPathPlugin.js +22 -4
  40. package/lib/WarnCaseSensitiveModulesPlugin.js +70 -2
  41. package/lib/WarnDeprecatedOptionPlugin.js +1 -1
  42. package/lib/WarnNoModeSetPlugin.js +16 -1
  43. package/lib/Watching.js +2 -3
  44. package/lib/WebpackError.js +3 -77
  45. package/lib/WebpackIsIncludedPlugin.js +1 -1
  46. package/lib/WebpackOptionsApply.js +13 -1
  47. package/lib/asset/AssetBytesGenerator.js +12 -8
  48. package/lib/asset/AssetGenerator.js +36 -22
  49. package/lib/asset/AssetModulesPlugin.js +6 -8
  50. package/lib/asset/AssetSourceGenerator.js +12 -8
  51. package/lib/buildChunkGraph.js +4 -6
  52. package/lib/cache/PackFileCacheStrategy.js +4 -4
  53. package/lib/cli.js +3 -1
  54. package/lib/config/defaults.js +197 -10
  55. package/lib/config/normalization.js +3 -1
  56. package/lib/css/CssGenerator.js +320 -105
  57. package/lib/css/CssInjectStyleRuntimeModule.js +44 -42
  58. package/lib/css/CssLoadingRuntimeModule.js +22 -4
  59. package/lib/{CssModule.js → css/CssModule.js} +15 -15
  60. package/lib/css/CssModulesPlugin.js +168 -88
  61. package/lib/css/CssParser.js +566 -269
  62. package/lib/css/walkCssTokens.js +148 -2
  63. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +1 -1
  64. package/lib/dependencies/CommonJsDependencyHelpers.js +63 -0
  65. package/lib/dependencies/CommonJsExportRequireDependency.js +54 -10
  66. package/lib/dependencies/CommonJsExportsParserPlugin.js +1 -1
  67. package/lib/dependencies/CommonJsFullRequireDependency.js +32 -9
  68. package/lib/dependencies/CommonJsImportsParserPlugin.js +112 -4
  69. package/lib/dependencies/CommonJsRequireDependency.js +67 -4
  70. package/lib/dependencies/ContextDependency.js +1 -1
  71. package/lib/dependencies/ContextDependencyHelpers.js +1 -1
  72. package/lib/dependencies/CreateRequireParserPlugin.js +1 -1
  73. package/lib/dependencies/CriticalDependencyWarning.js +1 -1
  74. package/lib/dependencies/CssIcssExportDependency.js +332 -67
  75. package/lib/dependencies/CssIcssImportDependency.js +49 -7
  76. package/lib/dependencies/CssIcssSymbolDependency.js +11 -3
  77. package/lib/dependencies/CssImportDependency.js +8 -0
  78. package/lib/dependencies/CssUrlDependency.js +28 -2
  79. package/lib/dependencies/HarmonyDetectionParserPlugin.js +22 -2
  80. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +8 -7
  81. package/lib/dependencies/HarmonyExportExpressionDependency.js +22 -14
  82. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +110 -3
  83. package/lib/dependencies/HarmonyImportDependency.js +10 -2
  84. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +22 -1
  85. package/lib/dependencies/HarmonyImportSpecifierDependency.js +1 -1
  86. package/lib/{HarmonyLinkingError.js → dependencies/HarmonyLinkingError.js} +5 -3
  87. package/lib/dependencies/HtmlInlineScriptDependency.js +133 -0
  88. package/lib/dependencies/HtmlInlineStyleDependency.js +101 -0
  89. package/lib/dependencies/HtmlScriptSrcDependency.js +557 -0
  90. package/lib/dependencies/HtmlSourceDependency.js +128 -0
  91. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +1 -1
  92. package/lib/dependencies/ImportParserPlugin.js +2 -2
  93. package/lib/dependencies/ImportPhase.js +1 -1
  94. package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +1 -1
  95. package/lib/{RequireJsStuffPlugin.js → dependencies/RequireJsStuffPlugin.js} +7 -7
  96. package/lib/dependencies/SystemPlugin.js +1 -1
  97. package/lib/dependencies/WebAssemblyImportDependency.js +1 -1
  98. package/lib/dependencies/WorkerPlugin.js +2 -2
  99. package/lib/{DelegatedModule.js → dll/DelegatedModule.js} +31 -31
  100. package/lib/{DelegatedModuleFactoryPlugin.js → dll/DelegatedModuleFactoryPlugin.js} +4 -4
  101. package/lib/{DelegatedPlugin.js → dll/DelegatedPlugin.js} +2 -2
  102. package/lib/{DllEntryPlugin.js → dll/DllEntryPlugin.js} +4 -4
  103. package/lib/{DllModule.js → dll/DllModule.js} +24 -24
  104. package/lib/{DllModuleFactory.js → dll/DllModuleFactory.js} +4 -4
  105. package/lib/{DllPlugin.js → dll/DllPlugin.js} +6 -5
  106. package/lib/{DllReferencePlugin.js → dll/DllReferencePlugin.js} +14 -14
  107. package/lib/{LibManifestPlugin.js → dll/LibManifestPlugin.js} +9 -9
  108. package/lib/{AsyncDependencyToInitialChunkError.js → errors/AsyncDependencyToInitialChunkError.js} +2 -2
  109. package/lib/errors/BuildCycleError.js +1 -1
  110. package/lib/{ChunkRenderError.js → errors/ChunkRenderError.js} +1 -1
  111. package/lib/{CodeGenerationError.js → errors/CodeGenerationError.js} +1 -1
  112. package/lib/{CommentCompilationWarning.js → errors/CommentCompilationWarning.js} +3 -3
  113. package/lib/{ConcurrentCompilationError.js → errors/ConcurrentCompilationError.js} +4 -2
  114. package/lib/{EnvironmentNotSupportAsyncWarning.js → errors/EnvironmentNotSupportAsyncWarning.js} +4 -4
  115. package/lib/{HookWebpackError.js → errors/HookWebpackError.js} +5 -5
  116. package/lib/{IgnoreErrorModuleFactory.js → errors/IgnoreErrorModuleFactory.js} +4 -4
  117. package/lib/{InvalidDependenciesModuleWarning.js → errors/InvalidDependenciesModuleWarning.js} +3 -3
  118. package/lib/errors/JSONParseError.js +114 -0
  119. package/lib/{ModuleBuildError.js → errors/ModuleBuildError.js} +5 -5
  120. package/lib/{ModuleDependencyError.js → errors/ModuleDependencyError.js} +2 -2
  121. package/lib/{ModuleDependencyWarning.js → errors/ModuleDependencyWarning.js} +4 -4
  122. package/lib/{ModuleError.js → errors/ModuleError.js} +5 -5
  123. package/lib/{ModuleHashingError.js → errors/ModuleHashingError.js} +1 -1
  124. package/lib/errors/ModuleNotFoundError.js +91 -0
  125. package/lib/{ModuleParseError.js → errors/ModuleParseError.js} +8 -6
  126. package/lib/{ModuleRestoreError.js → errors/ModuleRestoreError.js} +1 -1
  127. package/lib/{ModuleStoreError.js → errors/ModuleStoreError.js} +1 -1
  128. package/lib/{ModuleWarning.js → errors/ModuleWarning.js} +5 -5
  129. package/lib/{NodeStuffInWebError.js → errors/NodeStuffInWebError.js} +4 -4
  130. package/lib/errors/NonErrorEmittedError.js +28 -0
  131. package/lib/{UnhandledSchemeError.js → errors/UnhandledSchemeError.js} +2 -2
  132. package/lib/{UnsupportedFeatureWarning.js → errors/UnsupportedFeatureWarning.js} +3 -3
  133. package/lib/errors/WebpackError.js +84 -0
  134. package/lib/html/HtmlGenerator.js +379 -0
  135. package/lib/html/HtmlModulesPlugin.js +429 -0
  136. package/lib/html/HtmlParser.js +1489 -0
  137. package/lib/html/walkHtmlTokens.js +3249 -0
  138. package/lib/ids/IdHelpers.js +2 -1
  139. package/lib/index.js +36 -15
  140. package/lib/javascript/JavascriptModulesPlugin.js +91 -10
  141. package/lib/javascript/JavascriptParser.js +197 -16
  142. package/lib/javascript/JavascriptParserHelpers.js +1 -1
  143. package/lib/json/JsonParser.js +7 -16
  144. package/lib/library/AbstractLibraryPlugin.js +1 -1
  145. package/lib/library/EnableLibraryPlugin.js +1 -1
  146. package/lib/{FalseIIFEUmdWarning.js → library/FalseIIFEUmdWarning.js} +1 -1
  147. package/lib/library/ModuleLibraryPlugin.js +74 -0
  148. package/lib/node/NodeEnvironmentPlugin.js +4 -2
  149. package/lib/node/nodeConsole.js +113 -64
  150. package/lib/optimize/ConcatenatedModule.js +51 -6
  151. package/lib/optimize/InnerGraph.js +1 -1
  152. package/lib/optimize/InnerGraphPlugin.js +11 -1
  153. package/lib/optimize/MinMaxSizeWarning.js +4 -4
  154. package/lib/optimize/ModuleConcatenationPlugin.js +15 -7
  155. package/lib/optimize/RealContentHashPlugin.js +89 -26
  156. package/lib/optimize/SideEffectsFlagPlugin.js +112 -5
  157. package/lib/optimize/SplitChunksPlugin.js +5 -5
  158. package/lib/performance/AssetsOverSizeLimitWarning.js +2 -2
  159. package/lib/performance/EntrypointsOverSizeLimitWarning.js +2 -2
  160. package/lib/performance/NoAsyncChunksWarning.js +5 -3
  161. package/lib/performance/SizeLimitsPlugin.js +1 -1
  162. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +4 -1
  163. package/lib/rules/UseEffectRulePlugin.js +4 -3
  164. package/lib/runtime/AutoPublicPathRuntimeModule.js +3 -3
  165. package/lib/runtime/GetChunkFilenameRuntimeModule.js +5 -5
  166. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +119 -13
  167. package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +35 -0
  168. package/lib/schemes/DataUriPlugin.js +13 -1
  169. package/lib/schemes/VirtualUrlPlugin.js +1 -1
  170. package/lib/serialization/SerializerMiddleware.js +2 -2
  171. package/lib/sharing/ConsumeSharedPlugin.js +4 -10
  172. package/lib/sharing/ConsumeSharedRuntimeModule.js +8 -4
  173. package/lib/sharing/ProvideSharedModule.js +1 -1
  174. package/lib/sharing/ProvideSharedPlugin.js +5 -5
  175. package/lib/sharing/resolveMatchedConfigs.js +1 -1
  176. package/lib/stats/DefaultStatsFactoryPlugin.js +2 -2
  177. package/lib/stats/DefaultStatsPresetPlugin.js +1 -1
  178. package/lib/stats/DefaultStatsPrinterPlugin.js +1 -1
  179. package/lib/stats/StatsFactory.js +1 -1
  180. package/lib/typescript/TypeScriptPlugin.js +210 -0
  181. package/lib/url/URLParserPlugin.js +2 -2
  182. package/lib/util/AsyncQueue.js +2 -2
  183. package/lib/util/Hash.js +2 -2
  184. package/lib/util/LocConverter.js +53 -0
  185. package/lib/util/SortableSet.js +1 -1
  186. package/lib/util/cleverMerge.js +2 -2
  187. package/lib/util/comparators.js +3 -3
  188. package/lib/util/concatenate.js +3 -3
  189. package/lib/util/conventions.js +42 -1
  190. package/lib/util/createMappings.js +118 -0
  191. package/lib/{formatLocation.js → util/formatLocation.js} +2 -2
  192. package/lib/{SizeFormatHelpers.js → util/formatSize.js} +3 -1
  193. package/lib/util/fs.js +8 -8
  194. package/lib/util/hash/md4.js +1 -1
  195. package/lib/util/hash/xxhash64.js +1 -1
  196. package/lib/util/identifier.js +48 -0
  197. package/lib/util/internalSerializables.js +35 -19
  198. package/lib/util/magicComment.js +10 -7
  199. package/lib/util/parseJson.js +2 -73
  200. package/lib/util/source.js +21 -0
  201. package/lib/util/topologicalSort.js +69 -0
  202. package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +3 -4
  203. package/lib/wasm-async/AsyncWebAssemblyParser.js +1 -1
  204. package/lib/wasm-sync/UnsupportedWebAssemblyFeatureError.js +5 -3
  205. package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +1 -1
  206. package/lib/wasm-sync/WebAssemblyInInitialChunkError.js +5 -3
  207. package/lib/webpack.js +3 -1
  208. package/package.json +24 -22
  209. package/schemas/WebpackOptions.check.js +1 -1
  210. package/schemas/WebpackOptions.json +129 -12
  211. package/schemas/plugins/{DllPlugin.check.d.ts → HtmlGeneratorOptions.check.d.ts} +1 -1
  212. package/schemas/plugins/HtmlGeneratorOptions.check.js +6 -0
  213. package/schemas/plugins/HtmlGeneratorOptions.json +3 -0
  214. package/schemas/plugins/ProgressPlugin.check.js +1 -1
  215. package/schemas/plugins/ProgressPlugin.json +22 -0
  216. package/schemas/plugins/container/ContainerReferencePlugin.check.js +1 -1
  217. package/schemas/plugins/container/ContainerReferencePlugin.json +1 -0
  218. package/schemas/plugins/container/ExternalsType.check.js +1 -1
  219. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  220. package/schemas/plugins/container/ModuleFederationPlugin.json +1 -0
  221. package/schemas/plugins/{DllReferencePlugin.check.d.ts → css/CssAutoOrModuleParserOptions.check.d.ts} +1 -1
  222. package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +6 -0
  223. package/schemas/plugins/css/CssAutoOrModuleParserOptions.json +3 -0
  224. package/schemas/plugins/dll/DllPlugin.check.d.ts +7 -0
  225. package/schemas/plugins/dll/DllReferencePlugin.check.d.ts +7 -0
  226. package/types.d.ts +1153 -233
  227. package/lib/CaseSensitiveModulesWarning.js +0 -80
  228. package/lib/GraphHelpers.js +0 -49
  229. package/lib/NoModeWarning.js +0 -23
  230. package/lib/css/CssMergeStyleSheetsRuntimeModule.js +0 -57
  231. /package/lib/{AbstractMethodError.js → errors/AbstractMethodError.js} +0 -0
  232. /package/schemas/plugins/{DllPlugin.check.js → dll/DllPlugin.check.js} +0 -0
  233. /package/schemas/plugins/{DllPlugin.json → dll/DllPlugin.json} +0 -0
  234. /package/schemas/plugins/{DllReferencePlugin.check.js → dll/DllReferencePlugin.check.js} +0 -0
  235. /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,18 +14,19 @@ 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 */
26
28
  /** @typedef {import("../Module").BuildMeta} BuildMeta */
27
29
  /** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
28
- /** @typedef {import("../NormalModuleFactory").ModuleSettings} ModuleSettings */
29
30
  /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
30
31
  /** @typedef {import("../javascript/JavascriptParser").Range} Range */
31
32
 
@@ -63,6 +64,24 @@ const globToRegexp = (glob, cache) => {
63
64
  return regexp;
64
65
  };
65
66
 
67
+ /**
68
+ * @param {JavascriptParser} parser parser
69
+ * @param {number} start start position
70
+ * @param {number} end end position
71
+ * @returns {boolean} if annotation is found in the range
72
+ */
73
+ const hasNoSideEffectsNotation = (parser, start, end) => {
74
+ // Fast path
75
+ if (end - start < 18) return false;
76
+
77
+ const comments = parser.getComments([start, end]);
78
+ return comments.some(
79
+ (c) =>
80
+ c.type === "Block" &&
81
+ CompilerHintNotationRegExp.NoSideEffects.test(c.value)
82
+ );
83
+ };
84
+
66
85
  const PLUGIN_NAME = "SideEffectsFlagPlugin";
67
86
 
68
87
  class SideEffectsFlagPlugin {
@@ -114,7 +133,7 @@ class SideEffectsFlagPlugin {
114
133
  return module;
115
134
  });
116
135
  normalModuleFactory.hooks.module.tap(PLUGIN_NAME, (module, data) => {
117
- const settings = /** @type {ModuleSettings} */ (data.settings);
136
+ const settings = data.settings;
118
137
  if (typeof settings.sideEffects === "boolean") {
119
138
  if (module.factoryMeta === undefined) {
120
139
  module.factoryMeta = {};
@@ -129,7 +148,7 @@ class SideEffectsFlagPlugin {
129
148
  * @param {JavascriptParser} parser the parser
130
149
  * @returns {void}
131
150
  */
132
- const parserHandler = (parser) => {
151
+ const applySideEffectsStmtHandler = (parser) => {
133
152
  /** @type {undefined | Statement | ModuleDeclaration | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration} */
134
153
  let sideEffectsStatement;
135
154
  parser.hooks.program.tap(PLUGIN_NAME, () => {
@@ -260,6 +279,91 @@ class SideEffectsFlagPlugin {
260
279
  }
261
280
  });
262
281
  };
282
+
283
+ /**
284
+ * @param {JavascriptParser} parser the parser
285
+ * @returns {void}
286
+ */
287
+ const applyNoSideEffectsNotationHandler = (parser) => {
288
+ /** @type {Set<string>} */
289
+ let noSideEffectsFnNames;
290
+
291
+ parser.hooks.program.tap(PLUGIN_NAME, () => {
292
+ noSideEffectsFnNames = new Set();
293
+ });
294
+
295
+ // Detect on function declarations
296
+ // Covers:
297
+ // 1. function foo
298
+ // 2. export function foo
299
+ // 3. export default function foo
300
+ parser.hooks.preStatement.tap(PLUGIN_NAME, (statement) => {
301
+ if (parser.scope.topLevelScope !== true) return;
302
+ if (statement.type !== "FunctionDeclaration" || !statement.id) {
303
+ return;
304
+ }
305
+ const commentsStart = parser.prevStatement
306
+ ? /** @type {Range} */ (parser.prevStatement.range)[1]
307
+ : 0;
308
+ if (
309
+ hasNoSideEffectsNotation(
310
+ parser,
311
+ commentsStart,
312
+ /** @type {Range} */ (statement.range)[0]
313
+ )
314
+ ) {
315
+ noSideEffectsFnNames.add(statement.id.name);
316
+ }
317
+ });
318
+
319
+ // Detect on variable declarations with function init
320
+ parser.hooks.preDeclarator.tap(PLUGIN_NAME, (decl, statement) => {
321
+ if (parser.scope.topLevelScope !== true) return;
322
+ if (!decl.init || decl.id.type !== "Identifier") return;
323
+ if (!decl.init.type.endsWith("FunctionExpression")) return;
324
+
325
+ let hasAnnotation = false;
326
+ // Before the VariableDeclaration (only for const)
327
+ if (statement.kind === "const") {
328
+ const commentsStart = parser.prevStatement
329
+ ? /** @type {Range} */ (parser.prevStatement.range)[1]
330
+ : 0;
331
+ hasAnnotation = hasNoSideEffectsNotation(
332
+ parser,
333
+ commentsStart,
334
+ /** @type {Range} */ (statement.range)[0]
335
+ );
336
+ }
337
+
338
+ if (!hasAnnotation) {
339
+ hasAnnotation = hasNoSideEffectsNotation(
340
+ parser,
341
+ /** @type {Range} */ (decl.id.range)[1],
342
+ /** @type {Range} */ (decl.init.range)[0]
343
+ );
344
+ }
345
+ if (hasAnnotation) {
346
+ noSideEffectsFnNames.add(decl.id.name);
347
+ }
348
+ });
349
+
350
+ // Mark calls to annotated functions as pure
351
+ parser.hooks.isPure
352
+ .for("CallExpression")
353
+ .tap(PLUGIN_NAME, (expression, commentsStartPos) => {
354
+ const expr = /** @type {CallExpression} */ (expression);
355
+ if (expr.callee.type !== "Identifier") return;
356
+ if (!noSideEffectsFnNames.has(expr.callee.name)) return;
357
+ commentsStartPos = /** @type {Range} */ (expr.callee.range)[1];
358
+ for (const arg of expr.arguments) {
359
+ if (arg.type === "SpreadElement") return;
360
+ if (!parser.isPure(arg, commentsStartPos)) return;
361
+ commentsStartPos = /** @type {Range} */ (arg.range)[1];
362
+ }
363
+ return true;
364
+ });
365
+ };
366
+
263
367
  for (const key of [
264
368
  JAVASCRIPT_MODULE_TYPE_AUTO,
265
369
  JAVASCRIPT_MODULE_TYPE_ESM,
@@ -267,7 +371,10 @@ class SideEffectsFlagPlugin {
267
371
  ]) {
268
372
  normalModuleFactory.hooks.parser
269
373
  .for(key)
270
- .tap(PLUGIN_NAME, parserHandler);
374
+ .tap(PLUGIN_NAME, (parser) => {
375
+ applyNoSideEffectsNotationHandler(parser);
376
+ applySideEffectsStmtHandler(parser);
377
+ });
271
378
  }
272
379
  }
273
380
  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");
@@ -32,7 +32,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
32
32
  /** @typedef {import("../Module")} Module */
33
33
  /** @typedef {import("../Module").SourceType} SourceType */
34
34
  /** @typedef {import("../ModuleGraph")} ModuleGraph */
35
- /** @typedef {import("../TemplatedPathPlugin").TemplatePath} TemplatePath */
35
+ /** @typedef {import("../Chunk").ChunkFilenameTemplate} ChunkFilenameTemplate */
36
36
  /** @typedef {import("../util/deterministicGrouping").GroupedItems<Module>} DeterministicGroupingGroupedItemsForModule */
37
37
  /** @typedef {import("../util/deterministicGrouping").Options<Module>} DeterministicGroupingOptionsForModule */
38
38
  /** @typedef {import("../util/deterministicGrouping").Sizes} Sizes */
@@ -78,7 +78,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
78
78
  * @property {CountOfChunk=} minChunks
79
79
  * @property {CountOfRequest=} maxAsyncRequests
80
80
  * @property {CountOfRequest=} maxInitialRequests
81
- * @property {TemplatePath=} filename
81
+ * @property {ChunkFilenameTemplate=} filename
82
82
  * @property {string=} idHint
83
83
  * @property {string=} automaticNameDelimiter
84
84
  * @property {boolean=} reuseExistingChunk
@@ -101,7 +101,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
101
101
  * @property {CountOfChunk} minChunks
102
102
  * @property {CountOfRequest} maxAsyncRequests
103
103
  * @property {CountOfRequest} maxInitialRequests
104
- * @property {TemplatePath=} filename
104
+ * @property {ChunkFilenameTemplate=} filename
105
105
  * @property {string} idHint
106
106
  * @property {string} automaticNameDelimiter
107
107
  * @property {boolean} reuseExistingChunk
@@ -163,7 +163,7 @@ const MinMaxSizeWarning = require("./MinMaxSizeWarning");
163
163
  * @property {CountOfRequest} maxAsyncRequests
164
164
  * @property {CountOfRequest} maxInitialRequests
165
165
  * @property {boolean} hidePathInfo
166
- * @property {TemplatePath=} filename
166
+ * @property {ChunkFilenameTemplate=} filename
167
167
  * @property {string} automaticNameDelimiter
168
168
  * @property {GetCacheGroups} getCacheGroups
169
169
  * @property {GetNameFn} getName
@@ -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
  ];
@@ -26,14 +26,14 @@ class AutoPublicPathRuntimeModule extends RuntimeModule {
26
26
  const compilation = /** @type {Compilation} */ (this.compilation);
27
27
  const { scriptType, importMetaName, path, environment } =
28
28
  compilation.outputOptions;
29
+ const chunk = /** @type {Chunk} */ (this.chunk);
29
30
  const chunkName = compilation.getPath(
30
31
  JavascriptModulesPlugin.getChunkFilenameTemplate(
31
- /** @type {Chunk} */
32
- (this.chunk),
32
+ chunk,
33
33
  compilation.outputOptions
34
34
  ),
35
35
  {
36
- chunk: this.chunk,
36
+ chunk,
37
37
  contentHashType: "javascript"
38
38
  }
39
39
  );
@@ -14,14 +14,14 @@ const { first } = require("../util/SetHelpers");
14
14
  /** @typedef {import("../ChunkGraph")} ChunkGraph */
15
15
  /** @typedef {import("../Compilation")} Compilation */
16
16
  /** @typedef {import("../Compilation").HashWithLengthFunction} HashWithLengthFunction */
17
- /** @typedef {import("../TemplatedPathPlugin").TemplatePath} TemplatePath */
17
+ /** @typedef {import("../Chunk").ChunkFilenameTemplate} ChunkFilenameTemplate */
18
18
 
19
19
  class GetChunkFilenameRuntimeModule extends RuntimeModule {
20
20
  /**
21
21
  * @param {string} contentType the contentType to use the content hash for
22
22
  * @param {string} name kind of filename
23
23
  * @param {string} global function name to be assigned
24
- * @param {(chunk: Chunk) => TemplatePath | false} getFilenameForChunk functor to get the filename or function
24
+ * @param {(chunk: Chunk) => ChunkFilenameTemplate | false} getFilenameForChunk functor to get the filename or function
25
25
  * @param {boolean} allChunks when false, only async chunks are included
26
26
  */
27
27
  constructor(contentType, name, global, getFilenameForChunk, allChunks) {
@@ -30,7 +30,7 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
30
30
  this.contentType = contentType;
31
31
  /** @type {string} */
32
32
  this.global = global;
33
- /** @type {(chunk: Chunk) => TemplatePath | false} */
33
+ /** @type {(chunk: Chunk) => ChunkFilenameTemplate | false} */
34
34
  this.getFilenameForChunk = getFilenameForChunk;
35
35
  /** @type {boolean} */
36
36
  this.allChunks = allChunks;
@@ -49,7 +49,7 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
49
49
  const chunk = /** @type {Chunk} */ (this.chunk);
50
50
  const { runtimeTemplate } = compilation;
51
51
 
52
- /** @type {Map<string | TemplatePath, Set<Chunk>>} */
52
+ /** @type {Map<ChunkFilenameTemplate, Set<Chunk>>} */
53
53
  const chunkFilenames = new Map();
54
54
  let maxChunks = 0;
55
55
  /** @type {string | undefined} */
@@ -126,7 +126,7 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
126
126
 
127
127
  /**
128
128
  * @param {Chunk} c the chunk
129
- * @param {string | TemplatePath} chunkFilename the filename template for the chunk
129
+ * @param {ChunkFilenameTemplate} chunkFilename the filename template for the chunk
130
130
  * @returns {void}
131
131
  */
132
132
  const addStaticUrl = (c, chunkFilename) => {