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
@@ -159,6 +159,11 @@ class AsyncQueue {
159
159
  */
160
160
  add(item, callback) {
161
161
  if (this._stopped) return callback(new WebpackError("Queue was stopped"));
162
+ // skip async hook dispatch when unused — this runs per module × queue
163
+ if (!this.hooks.beforeAdd.isUsed()) {
164
+ this._add(item, callback);
165
+ return;
166
+ }
162
167
  this.hooks.beforeAdd.callAsync(item, (err) => {
163
168
  if (err) {
164
169
  callback(
@@ -166,42 +171,52 @@ class AsyncQueue {
166
171
  );
167
172
  return;
168
173
  }
169
- const key = this._getKey(item);
170
- const entry = this._entries.get(key);
171
- if (entry !== undefined) {
172
- if (entry.state === DONE_STATE) {
173
- if (inHandleResult++ > 3) {
174
- process.nextTick(() => callback(entry.error, entry.result));
175
- } else {
176
- callback(entry.error, entry.result);
177
- }
178
- inHandleResult--;
179
- } else if (entry.callbacks === undefined) {
180
- entry.callbacks = [callback];
174
+ this._add(item, callback);
175
+ });
176
+ }
177
+
178
+ /**
179
+ * Processes the provided item, after the beforeAdd hook.
180
+ * @param {T} item an item
181
+ * @param {Callback<R>} callback callback function
182
+ * @returns {void}
183
+ */
184
+ _add(item, callback) {
185
+ const key = this._getKey(item);
186
+ const entry = this._entries.get(key);
187
+ if (entry !== undefined) {
188
+ if (entry.state === DONE_STATE) {
189
+ if (inHandleResult++ > 3) {
190
+ process.nextTick(() => callback(entry.error, entry.result));
181
191
  } else {
182
- entry.callbacks.push(callback);
192
+ callback(entry.error, entry.result);
183
193
  }
184
- return;
185
- }
186
- const newEntry = new AsyncQueueEntry(item, callback);
187
- if (this._stopped) {
188
- this.hooks.added.call(item);
189
- this._root._activeTasks++;
190
- process.nextTick(() =>
191
- this._handleResult(newEntry, new WebpackError("Queue was stopped"))
192
- );
194
+ inHandleResult--;
195
+ } else if (entry.callbacks === undefined) {
196
+ entry.callbacks = [callback];
193
197
  } else {
194
- this._entries.set(key, newEntry);
195
- this._queued.enqueue(newEntry);
196
- const root = this._root;
197
- root._needProcessing = true;
198
- if (root._willEnsureProcessing === false) {
199
- root._willEnsureProcessing = true;
200
- setImmediate(root._ensureProcessing);
201
- }
202
- this.hooks.added.call(item);
198
+ entry.callbacks.push(callback);
203
199
  }
204
- });
200
+ return;
201
+ }
202
+ const newEntry = new AsyncQueueEntry(item, callback);
203
+ if (this._stopped) {
204
+ this.hooks.added.call(item);
205
+ this._root._activeTasks++;
206
+ process.nextTick(() =>
207
+ this._handleResult(newEntry, new WebpackError("Queue was stopped"))
208
+ );
209
+ } else {
210
+ this._entries.set(key, newEntry);
211
+ this._queued.enqueue(newEntry);
212
+ const root = this._root;
213
+ root._needProcessing = true;
214
+ if (root._willEnsureProcessing === false) {
215
+ root._willEnsureProcessing = true;
216
+ setImmediate(root._ensureProcessing);
217
+ }
218
+ this.hooks.added.call(item);
219
+ }
205
220
  }
206
221
 
207
222
  /**
@@ -357,6 +372,11 @@ class AsyncQueue {
357
372
  * @returns {void}
358
373
  */
359
374
  _startProcessing(entry) {
375
+ // skip async hook dispatch when unused — this runs per module × queue
376
+ if (!this.hooks.beforeStart.isUsed()) {
377
+ this._startProcessing2(entry);
378
+ return;
379
+ }
360
380
  this.hooks.beforeStart.callAsync(entry.item, (err) => {
361
381
  if (err) {
362
382
  this._handleResult(
@@ -365,20 +385,29 @@ class AsyncQueue {
365
385
  );
366
386
  return;
367
387
  }
368
- let inCallback = false;
369
- try {
370
- this._processor(entry.item, (e, r) => {
371
- inCallback = true;
372
- this._handleResult(entry, e, r);
373
- });
374
- } catch (err) {
375
- if (inCallback) throw err;
376
- this._handleResult(entry, /** @type {WebpackError} */ (err), null);
377
- }
378
- this.hooks.started.call(entry.item);
388
+ this._startProcessing2(entry);
379
389
  });
380
390
  }
381
391
 
392
+ /**
393
+ * Processes the provided entry, after the beforeStart hook.
394
+ * @param {AsyncQueueEntry<T, K, R>} entry the entry
395
+ * @returns {void}
396
+ */
397
+ _startProcessing2(entry) {
398
+ let inCallback = false;
399
+ try {
400
+ this._processor(entry.item, (e, r) => {
401
+ inCallback = true;
402
+ this._handleResult(entry, e, r);
403
+ });
404
+ } catch (err) {
405
+ if (inCallback) throw err;
406
+ this._handleResult(entry, /** @type {WebpackError} */ (err), null);
407
+ }
408
+ this.hooks.started.call(entry.item);
409
+ }
410
+
382
411
  /**
383
412
  * Processes the provided entry.
384
413
  * @param {AsyncQueueEntry<T, K, R>} entry the entry
@@ -387,45 +416,66 @@ class AsyncQueue {
387
416
  * @returns {void}
388
417
  */
389
418
  _handleResult(entry, err, result) {
419
+ // skip async hook dispatch when unused — this runs per module × queue
420
+ if (!this.hooks.result.isUsed()) {
421
+ this._handleResult2(entry, err, result);
422
+ return;
423
+ }
390
424
  this.hooks.result.callAsync(entry.item, err, result, (hookError) => {
391
- const error = hookError
392
- ? makeWebpackError(hookError, `AsyncQueue(${this._name}).hooks.result`)
393
- : err;
394
-
395
- const callback = /** @type {Callback<R>} */ (entry.callback);
396
- const callbacks = entry.callbacks;
397
- entry.state = DONE_STATE;
398
- entry.callback = undefined;
399
- entry.callbacks = undefined;
400
- entry.result = result;
401
- entry.error = error;
425
+ this._handleResult2(
426
+ entry,
427
+ hookError
428
+ ? makeWebpackError(
429
+ hookError,
430
+ `AsyncQueue(${this._name}).hooks.result`
431
+ )
432
+ : err,
433
+ result
434
+ );
435
+ });
436
+ }
402
437
 
403
- const root = this._root;
404
- root._activeTasks--;
405
- if (root._willEnsureProcessing === false && root._needProcessing) {
406
- root._willEnsureProcessing = true;
407
- setImmediate(root._ensureProcessing);
408
- }
438
+ /**
439
+ * Finalizes the provided entry, after the result hook.
440
+ * @param {AsyncQueueEntry<T, K, R>} entry the entry
441
+ * @param {(WebpackError | null)=} error error, if any
442
+ * @param {(R | null)=} result result, if any
443
+ * @returns {void}
444
+ */
445
+ _handleResult2(entry, error, result) {
446
+ const callback = /** @type {Callback<R>} */ (entry.callback);
447
+ const callbacks = entry.callbacks;
448
+ entry.state = DONE_STATE;
449
+ entry.callback = undefined;
450
+ entry.callbacks = undefined;
451
+ entry.result = result;
452
+ entry.error = error;
409
453
 
410
- if (inHandleResult++ > 3) {
411
- process.nextTick(() => {
412
- callback(error, result);
413
- if (callbacks !== undefined) {
414
- for (const callback of callbacks) {
415
- callback(error, result);
416
- }
417
- }
418
- });
419
- } else {
454
+ const root = this._root;
455
+ root._activeTasks--;
456
+ if (root._willEnsureProcessing === false && root._needProcessing) {
457
+ root._willEnsureProcessing = true;
458
+ setImmediate(root._ensureProcessing);
459
+ }
460
+
461
+ if (inHandleResult++ > 3) {
462
+ process.nextTick(() => {
420
463
  callback(error, result);
421
464
  if (callbacks !== undefined) {
422
465
  for (const callback of callbacks) {
423
466
  callback(error, result);
424
467
  }
425
468
  }
469
+ });
470
+ } else {
471
+ callback(error, result);
472
+ if (callbacks !== undefined) {
473
+ for (const callback of callbacks) {
474
+ callback(error, result);
475
+ }
426
476
  }
427
- inHandleResult--;
428
- });
477
+ }
478
+ inHandleResult--;
429
479
  }
430
480
 
431
481
  clear() {
@@ -41,7 +41,7 @@ const intersect = (sets) => {
41
41
  * @template T
42
42
  * @param {Set<T>} bigSet a Set which contains the original elements to compare against
43
43
  * @param {Set<T>} smallSet the set whose elements might be contained inside of bigSet
44
- * @returns {boolean} returns true if smallSet contains all elements inside of the bigSet
44
+ * @returns {boolean} returns true if bigSet contains all elements inside of smallSet
45
45
  */
46
46
  const isSubset = (bigSet, smallSet) => {
47
47
  if (bigSet.size < smallSet.size) return false;
@@ -41,21 +41,24 @@ const extractPair = (pair) => {
41
41
 
42
42
  /**
43
43
  * Layered map that supports child scopes while memoizing lookups from parent
44
- * scopes into the current layer.
44
+ * scopes. Layers form a linked parent chain, so `createChild` is O(1) instead
45
+ * of copying a layer array per scope. A layer's `Map` is only allocated on its
46
+ * first own write, and lookup results are memoized into the nearest
47
+ * `Map`-bearing layer of the walk — read-only layers (most block scopes) stay
48
+ * allocation-free and share their parent's memoized entries.
45
49
  * @template K
46
50
  * @template V
47
51
  */
48
52
  class StackedMap {
49
53
  /**
50
- * Creates a new map layer on top of an optional parent stack.
51
- * @param {Map<K, InternalCell<V>>[]=} parentStack an optional parent
54
+ * Creates a new map layer on top of an optional parent.
55
+ * @param {StackedMap<K, V>=} parent an optional parent map
52
56
  */
53
- constructor(parentStack) {
54
- /** @type {Map<K, InternalCell<V>>} */
55
- this.map = new Map();
56
- /** @type {Map<K, InternalCell<V>>[]} */
57
- this.stack = parentStack === undefined ? [] : [...parentStack];
58
- this.stack.push(this.map);
57
+ constructor(parent) {
58
+ /** @type {Map<K, InternalCell<V>> | undefined} */
59
+ this.map = undefined;
60
+ /** @type {StackedMap<K, V> | undefined} */
61
+ this.parent = parent;
59
62
  }
60
63
 
61
64
  /**
@@ -66,7 +69,10 @@ class StackedMap {
66
69
  * @returns {void}
67
70
  */
68
71
  set(item, value) {
69
- this.map.set(item, value === undefined ? UNDEFINED_MARKER : value);
72
+ (this.map || (this.map = new Map())).set(
73
+ item,
74
+ value === undefined ? UNDEFINED_MARKER : value
75
+ );
70
76
  }
71
77
 
72
78
  /**
@@ -76,80 +82,145 @@ class StackedMap {
76
82
  * @returns {void}
77
83
  */
78
84
  delete(item) {
79
- if (this.stack.length > 1) {
80
- this.map.set(item, TOMBSTONE);
81
- } else {
85
+ if (this.parent !== undefined) {
86
+ (this.map || (this.map = new Map())).set(item, TOMBSTONE);
87
+ } else if (this.map !== undefined) {
82
88
  this.map.delete(item);
83
89
  }
84
90
  }
85
91
 
86
92
  /**
87
93
  * Checks whether a key exists in the current scope chain, caching any parent
88
- * lookup result in the current layer.
94
+ * lookup result in the nearest `Map`-bearing layer.
89
95
  * @param {K} item the item to test
90
96
  * @returns {boolean} true if the item exists in this set
91
97
  */
92
98
  has(item) {
93
- const topValue = this.map.get(item);
94
- if (topValue !== undefined) {
95
- return topValue !== TOMBSTONE;
99
+ const own = this.map;
100
+ if (own !== undefined) {
101
+ const topValue = own.get(item);
102
+ if (topValue !== undefined) {
103
+ return topValue !== TOMBSTONE;
104
+ }
96
105
  }
97
- if (this.stack.length > 1) {
98
- for (let i = this.stack.length - 2; i >= 0; i--) {
99
- const value = this.stack[i].get(item);
106
+ /** @type {StackedMap<K, V> | undefined} */
107
+ let memoTarget = own !== undefined ? this : undefined;
108
+ /** @type {StackedMap<K, V> | undefined} */
109
+ let current = this.parent;
110
+ while (current !== undefined) {
111
+ const map = current.map;
112
+ if (map !== undefined) {
113
+ const value = map.get(item);
100
114
  if (value !== undefined) {
101
- this.map.set(item, value);
115
+ if (memoTarget !== undefined) {
116
+ /** @type {Map<K, InternalCell<V>>} */ (memoTarget.map).set(
117
+ item,
118
+ value
119
+ );
120
+ }
102
121
  return value !== TOMBSTONE;
103
122
  }
123
+ if (memoTarget === undefined) memoTarget = current;
104
124
  }
105
- this.map.set(item, TOMBSTONE);
125
+ current = current.parent;
126
+ }
127
+ if (memoTarget !== undefined) {
128
+ /** @type {Map<K, InternalCell<V>>} */ (memoTarget.map).set(
129
+ item,
130
+ TOMBSTONE
131
+ );
106
132
  }
107
133
  return false;
108
134
  }
109
135
 
110
136
  /**
111
137
  * Returns the visible value for a key, caching parent hits and misses in the
112
- * current layer.
138
+ * nearest `Map`-bearing layer so repeated lookups (from this layer or any
139
+ * sibling below that layer) answer with a single probe.
113
140
  * @param {K} item the key of the element to return
114
141
  * @returns {Cell<V>} the value of the element
115
142
  */
116
143
  get(item) {
117
- const topValue = this.map.get(item);
118
- if (topValue !== undefined) {
119
- return topValue === TOMBSTONE || topValue === UNDEFINED_MARKER
120
- ? undefined
121
- : topValue;
144
+ const own = this.map;
145
+ if (own !== undefined) {
146
+ const topValue = own.get(item);
147
+ if (topValue !== undefined) {
148
+ return topValue === TOMBSTONE || topValue === UNDEFINED_MARKER
149
+ ? undefined
150
+ : topValue;
151
+ }
122
152
  }
123
- if (this.stack.length > 1) {
124
- for (let i = this.stack.length - 2; i >= 0; i--) {
125
- const value = this.stack[i].get(item);
153
+ /** @type {StackedMap<K, V> | undefined} */
154
+ let memoTarget = own !== undefined ? this : undefined;
155
+ /** @type {StackedMap<K, V> | undefined} */
156
+ let current = this.parent;
157
+ while (current !== undefined) {
158
+ const map = current.map;
159
+ if (map !== undefined) {
160
+ const value = map.get(item);
126
161
  if (value !== undefined) {
127
- this.map.set(item, value);
162
+ if (memoTarget !== undefined) {
163
+ /** @type {Map<K, InternalCell<V>>} */ (memoTarget.map).set(
164
+ item,
165
+ value
166
+ );
167
+ }
128
168
  return value === TOMBSTONE || value === UNDEFINED_MARKER
129
169
  ? undefined
130
170
  : value;
131
171
  }
172
+ if (memoTarget === undefined) memoTarget = current;
132
173
  }
133
- this.map.set(item, TOMBSTONE);
174
+ current = current.parent;
175
+ }
176
+ if (memoTarget !== undefined) {
177
+ /** @type {Map<K, InternalCell<V>>} */ (memoTarget.map).set(
178
+ item,
179
+ TOMBSTONE
180
+ );
134
181
  }
135
182
  }
136
183
 
137
184
  /**
138
- * Collapses the stacked layers into a single concrete map.
185
+ * Collapses the parent chain into a single concrete map.
139
186
  */
140
187
  _compress() {
141
- if (this.stack.length === 1) return;
142
- this.map = new Map();
143
- for (const data of this.stack) {
144
- for (const pair of data) {
145
- if (pair[1] === TOMBSTONE) {
146
- this.map.delete(pair[0]);
147
- } else {
148
- this.map.set(pair[0], pair[1]);
188
+ if (this.parent === undefined) {
189
+ const map = this.map;
190
+ if (map === undefined) {
191
+ this.map = new Map();
192
+ return;
193
+ }
194
+ // a parent-less layer holds tombstones only as memoized misses
195
+ // (deletes remove outright) — drop them from the visible view
196
+ for (const pair of map) {
197
+ if (pair[1] === TOMBSTONE) map.delete(pair[0]);
198
+ }
199
+ return;
200
+ }
201
+ /** @type {StackedMap<K, V>[]} */
202
+ const layers = [];
203
+ /** @type {StackedMap<K, V> | undefined} */
204
+ let current = this;
205
+ do {
206
+ layers.push(current);
207
+ current = current.parent;
208
+ } while (current !== undefined);
209
+ const map = new Map();
210
+ for (let i = layers.length - 1; i >= 0; i--) {
211
+ const layerMap = layers[i].map;
212
+ if (layerMap !== undefined) {
213
+ for (const pair of layerMap) {
214
+ if (pair[1] === TOMBSTONE) {
215
+ map.delete(pair[0]);
216
+ } else {
217
+ map.set(pair[0], pair[1]);
218
+ }
149
219
  }
150
220
  }
151
221
  }
152
- this.stack = [this.map];
222
+ this.map = map;
223
+ this.parent = undefined;
153
224
  }
154
225
 
155
226
  /**
@@ -158,7 +229,7 @@ class StackedMap {
158
229
  */
159
230
  asArray() {
160
231
  this._compress();
161
- return [...this.map.keys()];
232
+ return [.../** @type {Map<K, InternalCell<V>>} */ (this.map).keys()];
162
233
  }
163
234
 
164
235
  /**
@@ -167,7 +238,7 @@ class StackedMap {
167
238
  */
168
239
  asSet() {
169
240
  this._compress();
170
- return new Set(this.map.keys());
241
+ return new Set(/** @type {Map<K, InternalCell<V>>} */ (this.map).keys());
171
242
  }
172
243
 
173
244
  /**
@@ -176,7 +247,10 @@ class StackedMap {
176
247
  */
177
248
  asPairArray() {
178
249
  this._compress();
179
- return Array.from(this.map.entries(), extractPair);
250
+ return Array.from(
251
+ /** @type {Map<K, InternalCell<V>>} */ (this.map).entries(),
252
+ extractPair
253
+ );
180
254
  }
181
255
 
182
256
  /**
@@ -193,7 +267,7 @@ class StackedMap {
193
267
  */
194
268
  get size() {
195
269
  this._compress();
196
- return this.map.size;
270
+ return /** @type {Map<K, InternalCell<V>>} */ (this.map).size;
197
271
  }
198
272
 
199
273
  /**
@@ -202,7 +276,7 @@ class StackedMap {
202
276
  * @returns {StackedMap<K, V>} child map
203
277
  */
204
278
  createChild() {
205
- return new StackedMap(this.stack);
279
+ return new StackedMap(this);
206
280
  }
207
281
  }
208
282
 
@@ -128,9 +128,9 @@ const fns = {
128
128
  * const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
129
129
  *
130
130
  * // Find the index of the first element greater than 5
131
- * const index1 = gt(arr, 5); // index1 === 3
131
+ * const index1 = gt(arr, 5); // index1 === 5
132
132
  *
133
- * // Find the index of the first element less than or equal to 5
133
+ * // Find the index of the last element less than or equal to 5
134
134
  * const index2 = le(arr, 5); // index2 === 4
135
135
  * ```
136
136
  */
@@ -25,11 +25,14 @@ const NAMESPACE_OBJECT_EXPORT = "__WEBPACK_NAMESPACE_OBJECT__";
25
25
  const getAllReferences = (variable) => {
26
26
  let set = variable.references;
27
27
  // Look for inner scope variables too (like in class Foo { t() { Foo } })
28
- const identifiers = new Set(variable.identifiers);
28
+ // identifiers is tiny (usually 1 declaration) — indexOf beats a Set here
29
+ const identifiers = variable.identifiers;
29
30
  for (const scope of variable.scope.childScopes) {
30
31
  for (const innerVar of scope.variables) {
31
- if (innerVar.identifiers.some((id) => identifiers.has(id))) {
32
- set = [...set, ...innerVar.references];
32
+ if (innerVar.identifiers.some((id) => identifiers.includes(id))) {
33
+ // copy-on-write to keep the common no-match case allocation-free
34
+ if (set === variable.references) set = [...set];
35
+ for (const ref of innerVar.references) set.push(ref);
33
36
  break;
34
37
  }
35
38
  }
@@ -113,6 +116,32 @@ const getPathInAst = (ast, node) => {
113
116
  }
114
117
  };
115
118
 
119
+ /** @type {Map<string, string[]>} */
120
+ const splittedInfoCache = new Map();
121
+
122
+ /**
123
+ * Returns path segments of the cleaned extra info.
124
+ * @param {string} extraInfo extra info
125
+ * @returns {string[]} cleaned path segments
126
+ */
127
+ const getSplittedInfo = (extraInfo) => {
128
+ let splittedInfo = splittedInfoCache.get(extraInfo);
129
+ if (splittedInfo === undefined) {
130
+ // bound the cache — extraInfo repeats for every renamed binding of a
131
+ // module, but distinct values grow with project size
132
+ if (splittedInfoCache.size >= 4096) splittedInfoCache.clear();
133
+ // Remove uncool stuff
134
+ splittedInfo = extraInfo
135
+ .replace(
136
+ /\.+\/|(?:\/index)?\.[a-zA-Z0-9]{1,4}(?:$|\s|\?)|\s*\+\s*\d+\s*modules/g,
137
+ ""
138
+ )
139
+ .split("/");
140
+ splittedInfoCache.set(extraInfo, splittedInfo);
141
+ }
142
+ return splittedInfo;
143
+ };
144
+
116
145
  /**
117
146
  * Returns found new name.
118
147
  * @param {string} oldName old name
@@ -131,15 +160,9 @@ function findNewName(oldName, usedNamed1, usedNamed2, extraInfo) {
131
160
  name = "namespaceObject";
132
161
  }
133
162
 
134
- // Remove uncool stuff
135
- extraInfo = extraInfo.replace(
136
- /\.+\/|(?:\/index)?\.[a-zA-Z0-9]{1,4}(?:$|\s|\?)|\s*\+\s*\d+\s*modules/g,
137
- ""
138
- );
139
-
140
- const splittedInfo = extraInfo.split("/");
141
- while (splittedInfo.length) {
142
- name = splittedInfo.pop() + (name ? `_${name}` : "");
163
+ const splittedInfo = getSplittedInfo(extraInfo);
164
+ for (let i = splittedInfo.length - 1; i >= 0; i--) {
165
+ name = splittedInfo[i] + (name ? `_${name}` : "");
143
166
  const nameIdent = Template.toIdentifier(name);
144
167
  if (
145
168
  !usedNamed1.has(nameIdent) &&
@@ -149,15 +172,18 @@ function findNewName(oldName, usedNamed1, usedNamed2, extraInfo) {
149
172
  }
150
173
  }
151
174
 
175
+ // `_${i}` is identifier-safe, so escaping the base once is equivalent to
176
+ // escaping every candidate — avoids two regexes per collision
177
+ const nameIdent = Template.toIdentifier(name);
152
178
  let i = 0;
153
- let nameWithNumber = Template.toIdentifier(`${name}_${i}`);
179
+ let nameWithNumber = `${nameIdent}_${i}`;
154
180
  while (
155
181
  usedNamed1.has(nameWithNumber) ||
156
182
  // eslint-disable-next-line no-unmodified-loop-condition
157
183
  (usedNamed2 && usedNamed2.has(nameWithNumber))
158
184
  ) {
159
185
  i++;
160
- nameWithNumber = Template.toIdentifier(`${name}_${i}`);
186
+ nameWithNumber = `${nameIdent}_${i}`;
161
187
  }
162
188
  return nameWithNumber;
163
189
  }
@@ -17,11 +17,19 @@ const createHooksRegistry = (createHooks) => {
17
17
  /** @type {WeakMap<import("../Compilation"), T>} */
18
18
  const map = new WeakMap();
19
19
  return (compilation) => {
20
- const Compilation = getCompilation();
21
- if (!(compilation instanceof Compilation)) {
22
- throw new TypeError(
23
- "The 'compilation' argument must be an instance of Compilation"
24
- );
20
+ if (!(compilation instanceof getCompilation())) {
21
+ // a compilation from another webpack copy fails instanceof — match the class name
22
+ const candidate =
23
+ /** @type {{ constructor?: { name: string } } | null} */ (compilation);
24
+ if (
25
+ !candidate ||
26
+ !candidate.constructor ||
27
+ candidate.constructor.name !== "Compilation"
28
+ ) {
29
+ throw new TypeError(
30
+ "The 'compilation' argument must be an instance of Compilation"
31
+ );
32
+ }
25
33
  }
26
34
  let hooks = map.get(compilation);
27
35
  if (hooks === undefined) {
@@ -28,9 +28,9 @@ const decodeDataURI = (uri) => {
28
28
  // CSS allows to use `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" style="stroke: rgb(223,224,225); stroke-width: 2px; fill: none; stroke-dasharray: 6px 3px" /></svg>`
29
29
  // so we return original body if we can't `decodeURIComponent`
30
30
  try {
31
- return Buffer.from(decodeURIComponent(body), "ascii");
31
+ return Buffer.from(decodeURIComponent(body), "utf8");
32
32
  } catch (_) {
33
- return Buffer.from(body, "ascii");
33
+ return Buffer.from(body, "utf8");
34
34
  }
35
35
  };
36
36