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
@@ -6,7 +6,6 @@
6
6
  "use strict";
7
7
 
8
8
  const querystring = require("querystring");
9
- const { getContext, runLoaders } = require("loader-runner");
10
9
  const {
11
10
  AsyncSeriesBailHook,
12
11
  HookMap,
@@ -31,6 +30,11 @@ const ModuleParseError = require("./errors/ModuleParseError");
31
30
  const ModuleWarning = require("./errors/ModuleWarning");
32
31
  const NonErrorEmittedError = require("./errors/NonErrorEmittedError");
33
32
  const UnhandledSchemeError = require("./errors/UnhandledSchemeError");
33
+ const {
34
+ createLoaderContext,
35
+ getContext,
36
+ runLoaders
37
+ } = require("./loaders/LoaderRunner");
34
38
  const LazySet = require("./util/LazySet");
35
39
  const { isSubset } = require("./util/SetHelpers");
36
40
  const { getScheme } = require("./util/URLAbsoluteSpecifier");
@@ -157,83 +161,132 @@ const recordSideEffectsBailout = (mod, moduleGraph, dep) => {
157
161
  );
158
162
  };
159
163
 
160
- // Maximum recursive descent depth before switching to the iterative walker.
161
- // #20986 reported overflow around 1300 modules in webpack 5.107.0 where each
162
- // step consumed two stack frames (`NormalModule.getSideEffectsConnectionState`
163
- // plus `HarmonyImportSideEffectDependency.getModuleEvaluationSideEffectsState`).
164
- // `walkSideEffectsRecursive` folds the second call into the first and uses
165
- // one frame per module, so this limit caps the native stack at half the depth
166
- // where the original code overflowed — well within the safe range across
167
- // platforms while keeping the common (shallow) case purely recursive.
168
- const SIDE_EFFECTS_RECURSION_LIMIT = 2000;
169
-
170
164
  /**
171
- * Iterative form of the side-effects walker. Used as a fallback once the
172
- * recursive form reaches `SIDE_EFFECTS_RECURSION_LIMIT` so deep chains
173
- * (#20986) don't overflow V8's stack. Safe to enter while ancestors set
174
- * `_isEvaluatingSideEffects` on their own modules — those are treated as
175
- * `CIRCULAR_CONNECTION` if revisited, matching the original recursive
176
- * behavior.
177
- * @param {NormalModule} rootMod the module to walk
165
+ * Walks the `HarmonyImportSideEffectDependency` graph to decide how `rootMod`
166
+ * connects to a referrer when consumed for its side effects only.
167
+ *
168
+ * Iterative (explicit work stack) so deep import chains never approach V8's
169
+ * recursion limit — the overflow behind #20986 — with no separate recursive
170
+ * form or depth cap. Cycles use Tarjan's `index`/`lowlink`: a module's result
171
+ * is memoized on `_sideEffectsStateGraph` only when it is context-independent
172
+ * (cycle-free, or the root of its strongly-connected component), i.e. exactly
173
+ * when the result cannot depend on which ancestors are mid-walk.
174
+ *
175
+ * The previous walker disabled memoization for the whole walk the moment any
176
+ * cycle appeared (one global `circular` flag). With diamond-shaped graphs that
177
+ * made the walk exponential, so a single circular import could blow up an
178
+ * otherwise-linear graph. Per-module lowlink keeps the cycle-free majority
179
+ * memoized while a cycle exists elsewhere.
180
+ *
181
+ * Caching under `lowlink === index` is conservative: an imprecise lowlink can
182
+ * only skip caching (a later recompute yields the same value), never memoize a
183
+ * state that depended on stack context. `true` is monotonic and always cached.
184
+ * A non-`NormalModule` dependency (e.g. `ConcatenatedModule` re-entering this
185
+ * method) is treated as a taint so its chain is never memoized, and any module
186
+ * already flagged `_isEvaluatingSideEffects` (this walk or an outer re-entrant
187
+ * one) counts as circular, matching the previous walker.
188
+ * @param {NormalModule} rootMod the module being walked
178
189
  * @param {ModuleGraph} moduleGraph the module graph
179
- * @param {SideEffectsWalkContext} ctx per-walk cycle-tracking context
190
+ * @param {EXPECTED_ANY} SideEffectDep `HarmonyImportSideEffectDependency` constructor, resolved once at the entry
180
191
  * @returns {ConnectionState} the side-effects connection state
181
192
  */
182
- const walkSideEffectsIterative = (rootMod, moduleGraph, ctx) => {
183
- const SideEffectDep = getHarmonyImportSideEffectDependency();
193
+ const walkSideEffects = (rootMod, moduleGraph, SideEffectDep) => {
194
+ // Context-independent state without descending; `undefined` => walk deps.
195
+ /**
196
+ * @param {NormalModule} mod module
197
+ * @returns {ConnectionState | undefined} resolved state or undefined
198
+ */
199
+ const quick = (mod) => {
200
+ if (mod._sideEffectsStateGraph === moduleGraph) {
201
+ return /** @type {ConnectionState} */ (mod._sideEffectsStateValue);
202
+ }
203
+ const fm = mod.factoryMeta;
204
+ if (fm !== undefined) {
205
+ if (fm.sideEffectFree) return false;
206
+ if (fm.sideEffectFree === false) return true;
207
+ }
208
+ if (!(mod.buildMeta !== undefined && mod.buildMeta.sideEffectFree)) {
209
+ return true;
210
+ }
211
+ return undefined;
212
+ };
184
213
 
214
+ const q0 = quick(rootMod);
215
+ if (q0 !== undefined) return q0;
216
+
217
+ /** @type {Map<NormalModule, number>} module -> Tarjan index */
218
+ const indexOf = new Map();
219
+ /** @type {Map<NormalModule, number>} module -> Tarjan lowlink */
220
+ const lowOf = new Map();
221
+ // Parallel frame arrays, to avoid a per-frame object allocation.
185
222
  /** @type {NormalModule[]} */
186
- const modStack = [rootMod];
223
+ const fMod = [];
187
224
  /** @type {Dependency[][]} */
188
- const depsStack = [rootMod.dependencies];
189
- const indexStack = [0];
225
+ const fDeps = [];
226
+ /** @type {number[]} */
227
+ const fIdx = [];
190
228
  /** @type {ConnectionState[]} */
191
- const currentStack = [false];
192
- rootMod._isEvaluatingSideEffects = true;
229
+ const fCur = [];
230
+ let counter = 0;
193
231
 
194
232
  /**
195
- * Result from a just-popped child frame, to be applied to the new
196
- * top's current dep. `undefined` means "no pending; advance".
233
+ * @param {NormalModule} mod module to push a frame for
234
+ */
235
+ const enter = (mod) => {
236
+ indexOf.set(mod, counter);
237
+ lowOf.set(mod, counter);
238
+ counter++;
239
+ mod._isEvaluatingSideEffects = true;
240
+ fMod.push(mod);
241
+ fDeps.push(mod.dependencies);
242
+ fIdx.push(0);
243
+ fCur.push(false);
244
+ };
245
+
246
+ enter(rootMod);
247
+ /** @type {ConnectionState} the just-popped frame's result */
248
+ let result = false;
249
+ /**
250
+ * Result of a just-popped child frame, to apply to the new top's current
251
+ * dep. `undefined` means "no pending; advance normally".
197
252
  * @type {ConnectionState | undefined}
198
253
  */
199
254
  let pending;
200
255
 
201
- while (modStack.length > 0) {
202
- const top = modStack.length - 1;
203
- const topMod = modStack[top];
204
- const deps = depsStack[top];
205
- let index = indexStack[top];
206
- let current = currentStack[top];
256
+ while (fMod.length > 0) {
257
+ const top = fMod.length - 1;
258
+ const mod = fMod[top];
259
+ const deps = fDeps[top];
260
+ let i = fIdx[top];
261
+ let current = fCur[top];
207
262
 
263
+ // Apply a popped child's result to the dep that spawned it.
208
264
  if (pending !== undefined) {
209
265
  const state = pending;
210
266
  pending = undefined;
211
- const dep = deps[index];
212
-
267
+ const dep = deps[i];
213
268
  if (state === true) {
214
- recordSideEffectsBailout(topMod, moduleGraph, dep);
215
- topMod._isEvaluatingSideEffects = false;
216
- // `true` is monotonic — safe to memoize regardless of cycle
217
- // status, matching the direct-bailout branch below.
218
- topMod._sideEffectsStateGraph = moduleGraph;
219
- topMod._sideEffectsStateValue = true;
220
- modStack.pop();
221
- depsStack.pop();
222
- indexStack.pop();
223
- currentStack.pop();
269
+ recordSideEffectsBailout(mod, moduleGraph, dep);
270
+ mod._sideEffectsStateGraph = moduleGraph;
271
+ mod._sideEffectsStateValue = true;
272
+ mod._isEvaluatingSideEffects = false;
273
+ fMod.pop();
274
+ fDeps.pop();
275
+ fIdx.pop();
276
+ fCur.pop();
277
+ result = true;
224
278
  pending = true;
225
279
  continue;
226
280
  }
227
281
  if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
228
282
  current = ModuleGraphConnection.addConnectionStates(current, state);
229
283
  }
230
- index++;
284
+ i++;
231
285
  }
232
286
 
233
287
  let descended = false;
234
- const depCount = deps.length;
235
- while (index < depCount) {
236
- const dep = deps[index];
288
+ while (i < deps.length) {
289
+ const dep = deps[i];
237
290
  /** @type {ConnectionState} */
238
291
  let state;
239
292
 
@@ -242,75 +295,53 @@ const walkSideEffectsIterative = (rootMod, moduleGraph, ctx) => {
242
295
  if (!refModule) {
243
296
  state = true;
244
297
  } else if (refModule instanceof NormalModule) {
245
- // Cache hit
246
- if (refModule._sideEffectsStateGraph === moduleGraph) {
247
- state = /** @type {ConnectionState} */ (
248
- refModule._sideEffectsStateValue
298
+ if (refModule._isEvaluatingSideEffects) {
299
+ // On the current stack (or an outer re-entrant walk) => cycle.
300
+ state = ModuleGraphConnection.CIRCULAR_CONNECTION;
301
+ const ri = indexOf.get(refModule);
302
+ lowOf.set(
303
+ mod,
304
+ Math.min(
305
+ /** @type {number} */ (lowOf.get(mod)),
306
+ ri === undefined ? -1 : ri
307
+ )
249
308
  );
250
- }
251
- // Fast-path checks inlined to avoid the helper call.
252
- else if (refModule.factoryMeta !== undefined) {
253
- if (refModule.factoryMeta.sideEffectFree) {
254
- state = false;
255
- } else if (refModule.factoryMeta.sideEffectFree === false) {
256
- state = true;
257
- } else if (!(
258
- refModule.buildMeta !== undefined &&
259
- refModule.buildMeta.sideEffectFree
260
- )) {
261
- state = true;
262
- } else if (refModule._isEvaluatingSideEffects) {
263
- ctx.circular = true;
264
- state = ModuleGraphConnection.CIRCULAR_CONNECTION;
309
+ } else {
310
+ const q = quick(refModule);
311
+ if (q !== undefined) {
312
+ state = q;
265
313
  } else {
266
- // Descend
267
- indexStack[top] = index;
268
- currentStack[top] = current;
269
- refModule._isEvaluatingSideEffects = true;
270
- modStack.push(refModule);
271
- depsStack.push(refModule.dependencies);
272
- indexStack.push(0);
273
- currentStack.push(false);
314
+ // Descend: pause this frame, walk the child next.
315
+ fIdx[top] = i;
316
+ fCur[top] = current;
317
+ enter(refModule);
274
318
  descended = true;
275
319
  break;
276
320
  }
277
- } else if (!(
278
- refModule.buildMeta !== undefined &&
279
- refModule.buildMeta.sideEffectFree
280
- )) {
281
- state = true;
282
- } else if (refModule._isEvaluatingSideEffects) {
283
- ctx.circular = true;
284
- state = ModuleGraphConnection.CIRCULAR_CONNECTION;
285
- } else {
286
- // Descend
287
- indexStack[top] = index;
288
- currentStack[top] = current;
289
- refModule._isEvaluatingSideEffects = true;
290
- modStack.push(refModule);
291
- depsStack.push(refModule.dependencies);
292
- indexStack.push(0);
293
- currentStack.push(false);
294
- descended = true;
295
- break;
296
321
  }
297
322
  } else {
298
- ctx.circular = true;
323
+ // Non-NormalModule (e.g. ConcatenatedModule delegating back
324
+ // through here) resolves via a re-entrant walk that may see our
325
+ // in-progress modules as circular, so taint this chain: never
326
+ // memoize it.
299
327
  state = refModule.getSideEffectsConnectionState(moduleGraph);
328
+ lowOf.set(mod, -1);
300
329
  }
301
330
  } else {
302
331
  state = dep.getModuleEvaluationSideEffectsState(moduleGraph);
303
332
  }
304
333
 
305
334
  if (state === true) {
306
- recordSideEffectsBailout(topMod, moduleGraph, dep);
307
- topMod._isEvaluatingSideEffects = false;
308
- topMod._sideEffectsStateGraph = moduleGraph;
309
- topMod._sideEffectsStateValue = true;
310
- modStack.pop();
311
- depsStack.pop();
312
- indexStack.pop();
313
- currentStack.pop();
335
+ recordSideEffectsBailout(mod, moduleGraph, dep);
336
+ // `true` is monotonic — always safe to memoize.
337
+ mod._sideEffectsStateGraph = moduleGraph;
338
+ mod._sideEffectsStateValue = true;
339
+ mod._isEvaluatingSideEffects = false;
340
+ fMod.pop();
341
+ fDeps.pop();
342
+ fIdx.pop();
343
+ fCur.pop();
344
+ result = true;
314
345
  pending = true;
315
346
  descended = true;
316
347
  break;
@@ -318,304 +349,38 @@ const walkSideEffectsIterative = (rootMod, moduleGraph, ctx) => {
318
349
  if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
319
350
  current = ModuleGraphConnection.addConnectionStates(current, state);
320
351
  }
321
- index++;
352
+ i++;
322
353
  }
323
354
 
324
355
  if (descended) continue;
325
356
 
326
- topMod._isEvaluatingSideEffects = false;
327
- if (!ctx.circular) {
328
- topMod._sideEffectsStateGraph = moduleGraph;
329
- topMod._sideEffectsStateValue = current;
357
+ // `mod` finished without a `true` bailout.
358
+ mod._isEvaluatingSideEffects = false;
359
+ // Memoize only when the result is context-independent: no back-edge in
360
+ // this subtree reached above `mod` (a cycle-free module or an SCC root).
361
+ if (lowOf.get(mod) === indexOf.get(mod)) {
362
+ mod._sideEffectsStateGraph = moduleGraph;
363
+ mod._sideEffectsStateValue = current;
330
364
  }
365
+ fMod.pop();
366
+ fDeps.pop();
367
+ fIdx.pop();
368
+ fCur.pop();
369
+ result = current;
331
370
  pending = current;
332
- modStack.pop();
333
- depsStack.pop();
334
- indexStack.pop();
335
- currentStack.pop();
336
- }
337
-
338
- return /** @type {ConnectionState} */ (pending);
339
- };
340
-
341
- /**
342
- * @typedef {object} SideEffectsWalkContext
343
- * @property {boolean} circular whether a cycle was seen anywhere in this walk
344
- */
345
-
346
- /**
347
- * Walks back up a stack of linear-chain ancestors, applying the result
348
- * `state` of the chain's tail to each ancestor. Each ancestor in the
349
- * stack had exactly one `HarmonyImportSideEffectDependency` returning
350
- * `state`, so its result is just `state` (with the usual aggregation
351
- * rules) and we can avoid building per-frame `current` accumulators.
352
- * @param {(NormalModule | Dependency)[] | null} ancestors interleaved stack of `[mod, sideEffectDep, mod, sideEffectDep, …]` in descent order; `null` if there were none
353
- * @param {ConnectionState} state result from the chain's tail
354
- * @param {ModuleGraph} moduleGraph the module graph
355
- * @param {SideEffectsWalkContext} ctx per-walk cycle-tracking context
356
- * @returns {ConnectionState} the root ancestor's result
357
- */
358
- const propagateLinearResult = (ancestors, state, moduleGraph, ctx) => {
359
- if (ancestors === null) return state;
360
- while (ancestors.length > 0) {
361
- const dep = /** @type {Dependency} */ (ancestors.pop());
362
- const ancestor = /** @type {NormalModule} */ (ancestors.pop());
363
- ancestor._isEvaluatingSideEffects = false;
364
-
365
- if (state === true) {
366
- recordSideEffectsBailout(ancestor, moduleGraph, dep);
367
- // `true` is monotonic — safe to cache regardless of cycle status.
368
- ancestor._sideEffectsStateGraph = moduleGraph;
369
- ancestor._sideEffectsStateValue = true;
370
- } else if (state === ModuleGraphConnection.CIRCULAR_CONNECTION) {
371
- // CIRCULAR_CONNECTION is filtered before folding into `current`,
372
- // so the ancestor's `current` stays at its initial `false`. From
373
- // this point upward the propagated state is `false`, and the
374
- // cycle taint prevents memoization further up (handled by
375
- // `ctx.circular`).
376
- state = false;
377
- } else if (!ctx.circular) {
378
- ancestor._sideEffectsStateGraph = moduleGraph;
379
- ancestor._sideEffectsStateValue = state;
380
- }
381
- }
382
- return state;
383
- };
384
-
385
- /**
386
- * Recursive form of the side-effects walker. Folds the descent through
387
- * `HarmonyImportSideEffectDependency.getModuleEvaluationSideEffectsState`
388
- * directly into the loop so each module costs only one V8 stack frame
389
- * (vs. two in the original recursive code).
390
- *
391
- * Linear-chain heads (modules with exactly one
392
- * `HarmonyImportSideEffectDependency` to another `NormalModule`) are
393
- * walked iteratively inside the function via an explicit
394
- * `linearAncestors` stack — no additional V8 frame per descent — and
395
- * their results are propagated back up by `propagateLinearResult`. This
396
- * keeps stack consumption at O(1) for the common deep-import-chain
397
- * pattern that motivated #20986 and also avoids the heavier iterative
398
- * fallback.
399
- *
400
- * Falls back to `walkSideEffectsIterative` only when a *non-linear*
401
- * walk reaches `SIDE_EFFECTS_RECURSION_LIMIT` — i.e. a deep tree, where
402
- * each level genuinely needs its own recursion frame.
403
- *
404
- * Caches the result on the module when the walk did not encounter a
405
- * cycle, so subsequent queries (e.g. repeated lookups during
406
- * `SideEffectsFlagPlugin`'s incoming-connection optimization and its
407
- * `exportInfo.getTarget` callbacks) return in O(1).
408
- * @param {NormalModule} mod the module being walked
409
- * @param {ModuleGraph} moduleGraph the module graph
410
- * @param {number} depth current recursion depth (only counts true V8 frames)
411
- * @param {EXPECTED_ANY} SideEffectDep `HarmonyImportSideEffectDependency` constructor, resolved once at the public entry to avoid repeated `require` lookups in the recursive call
412
- * @param {SideEffectsWalkContext} ctx per-walk cycle-tracking context
413
- * @returns {ConnectionState} the side-effects connection state
414
- */
415
- const walkSideEffectsRecursive = (
416
- mod,
417
- moduleGraph,
418
- depth,
419
- SideEffectDep,
420
- ctx
421
- ) => {
422
- // Interleaved `[mod, linearDep, mod, linearDep, …]` for the linear
423
- // chain head; `null` until the first descent.
424
- /** @type {(NormalModule | Dependency)[] | null} */
425
- let linearAncestors = null;
426
-
427
- // Walk the linear-chain head iteratively. Every loop iteration peels
428
- // off one module without consuming a V8 stack frame.
429
- while (true) {
430
- if (mod._sideEffectsStateGraph === moduleGraph) {
431
- return propagateLinearResult(
432
- linearAncestors,
433
- /** @type {ConnectionState} */ (mod._sideEffectsStateValue),
434
- moduleGraph,
435
- ctx
371
+ if (fMod.length > 0) {
372
+ const parent = fMod[fMod.length - 1];
373
+ lowOf.set(
374
+ parent,
375
+ Math.min(
376
+ /** @type {number} */ (lowOf.get(parent)),
377
+ /** @type {number} */ (lowOf.get(mod))
378
+ )
436
379
  );
437
380
  }
438
-
439
- if (mod.factoryMeta !== undefined) {
440
- if (mod.factoryMeta.sideEffectFree) {
441
- return propagateLinearResult(linearAncestors, false, moduleGraph, ctx);
442
- }
443
- if (mod.factoryMeta.sideEffectFree === false) {
444
- return propagateLinearResult(linearAncestors, true, moduleGraph, ctx);
445
- }
446
- }
447
- if (!(mod.buildMeta !== undefined && mod.buildMeta.sideEffectFree)) {
448
- return propagateLinearResult(linearAncestors, true, moduleGraph, ctx);
449
- }
450
- if (mod._isEvaluatingSideEffects) {
451
- ctx.circular = true;
452
- return propagateLinearResult(
453
- linearAncestors,
454
- ModuleGraphConnection.CIRCULAR_CONNECTION,
455
- moduleGraph,
456
- ctx
457
- );
458
- }
459
-
460
- // A real ESM module's `dependencies` typically include one
461
- // `HarmonyImportSideEffectDependency` plus several non-recursive deps
462
- // (export specifiers, const dependencies, …) that report
463
- // `false`/`CIRCULAR_CONNECTION` from
464
- // `getModuleEvaluationSideEffectsState`. Walk the deps in order
465
- // here: as long as at most one is a `SideEffectDep` and no
466
- // non-recursive dep triggers a bailout or contributes a non-`false`
467
- // state, we can still tail-call iteratively through that one
468
- // `SideEffectDep` — no V8 frame needed. This is what keeps the
469
- // 1300-module cyclic chain from #20986 from overflowing V8's stack
470
- // even though each generated module has multiple `dependencies`.
471
- const deps = mod.dependencies;
472
- /** @type {Dependency | null} */
473
- let linearDep = null;
474
- /** @type {ConnectionState} */
475
- let nonRecursiveCurrent = false;
476
- let linearOk = true;
477
- for (let i = 0; i < deps.length; i++) {
478
- const dep = deps[i];
479
- if (dep instanceof SideEffectDep) {
480
- if (linearDep !== null) {
481
- // Two `SideEffectDep`s in the same module — fall back to
482
- // the general walk so each can recurse normally.
483
- linearOk = false;
484
- break;
485
- }
486
- linearDep = dep;
487
- } else {
488
- const state = dep.getModuleEvaluationSideEffectsState(moduleGraph);
489
- if (state === true) {
490
- recordSideEffectsBailout(mod, moduleGraph, dep);
491
- mod._sideEffectsStateGraph = moduleGraph;
492
- mod._sideEffectsStateValue = true;
493
- return propagateLinearResult(linearAncestors, true, moduleGraph, ctx);
494
- }
495
- if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
496
- nonRecursiveCurrent = ModuleGraphConnection.addConnectionStates(
497
- nonRecursiveCurrent,
498
- state
499
- );
500
- }
501
- }
502
- }
503
-
504
- if (!linearOk || nonRecursiveCurrent !== false) {
505
- // Multiple `SideEffectDep`s, or a non-recursive dep contributed
506
- // a non-`false` state (e.g. `TRANSITIVE_ONLY`). The linear
507
- // propagation rule "ancestor's current = chain state" no longer
508
- // holds, so fall back to the general walk.
509
- break;
510
- }
511
-
512
- if (linearDep === null) {
513
- // No `SideEffectDep` — the module is a leaf as far as the
514
- // side-effects graph is concerned. Cache and propagate `false`.
515
- if (!ctx.circular) {
516
- mod._sideEffectsStateGraph = moduleGraph;
517
- mod._sideEffectsStateValue = false;
518
- }
519
- return propagateLinearResult(linearAncestors, false, moduleGraph, ctx);
520
- }
521
-
522
- const refModule = moduleGraph.getModule(linearDep);
523
- if (!refModule) {
524
- recordSideEffectsBailout(mod, moduleGraph, linearDep);
525
- mod._sideEffectsStateGraph = moduleGraph;
526
- mod._sideEffectsStateValue = true;
527
- return propagateLinearResult(linearAncestors, true, moduleGraph, ctx);
528
- }
529
- if (!(refModule instanceof NormalModule)) {
530
- // Non-NormalModule's `getSideEffectsConnectionState` re-enters
531
- // the public method; defer to the general walk for safety.
532
- break;
533
- }
534
-
535
- mod._isEvaluatingSideEffects = true;
536
- if (linearAncestors === null) linearAncestors = [];
537
- // Push (mod, linearDep) so `propagateLinearResult` records bailouts
538
- // against the actual `SideEffectDep` that triggered the descent —
539
- // which may not be `dependencies[0]` when the module also has
540
- // export / const dependencies.
541
- linearAncestors.push(mod, linearDep);
542
- mod = refModule;
543
- continue;
544
381
  }
545
382
 
546
- // Non-linear walk. Each genuine recursive call costs one V8 frame, so
547
- // honour the depth limit here.
548
- if (depth >= SIDE_EFFECTS_RECURSION_LIMIT) {
549
- return propagateLinearResult(
550
- linearAncestors,
551
- walkSideEffectsIterative(mod, moduleGraph, ctx),
552
- moduleGraph,
553
- ctx
554
- );
555
- }
556
-
557
- mod._isEvaluatingSideEffects = true;
558
- /** @type {ConnectionState} */
559
- let current = false;
560
-
561
- for (const dep of mod.dependencies) {
562
- /** @type {ConnectionState} */
563
- let state;
564
- if (dep instanceof SideEffectDep) {
565
- const refModule = moduleGraph.getModule(dep);
566
- if (!refModule) {
567
- state = true;
568
- } else if (refModule instanceof NormalModule) {
569
- state = walkSideEffectsRecursive(
570
- refModule,
571
- moduleGraph,
572
- depth + 1,
573
- SideEffectDep,
574
- ctx
575
- );
576
- } else {
577
- // Non-NormalModule's `getSideEffectsConnectionState` (notably
578
- // `ConcatenatedModule` delegating to its root) re-enters the
579
- // public method and may walk through modules that the outer
580
- // walk has marked as evaluating. We can't observe whether
581
- // the inner walk hit a cycle that reflected the outer's
582
- // state, so treat the walk as cycle-tainted and skip the
583
- // cache for safety.
584
- ctx.circular = true;
585
- state = refModule.getSideEffectsConnectionState(moduleGraph);
586
- }
587
- } else {
588
- state = dep.getModuleEvaluationSideEffectsState(moduleGraph);
589
- }
590
-
591
- if (state === true) {
592
- recordSideEffectsBailout(mod, moduleGraph, dep);
593
- mod._isEvaluatingSideEffects = false;
594
- // `true` is monotonic — once any dep declares side effects, the
595
- // answer is `true` regardless of how cycles resolve, so it's
596
- // always safe to memoize.
597
- mod._sideEffectsStateGraph = moduleGraph;
598
- mod._sideEffectsStateValue = true;
599
- return propagateLinearResult(linearAncestors, true, moduleGraph, ctx);
600
- }
601
- if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
602
- current = ModuleGraphConnection.addConnectionStates(current, state);
603
- }
604
- }
605
-
606
- mod._isEvaluatingSideEffects = false;
607
-
608
- // Only memoize when no cycle has been observed anywhere in the walk
609
- // since the public entry. A cycle anywhere can affect any ancestor's
610
- // result (the back-edge target's contribution is hidden by
611
- // CIRCULAR_CONNECTION short-circuiting), so this single flag is the
612
- // conservative-but-cheap approximation of "this subtree's result is
613
- // independent of cycle context". The public entry resets the flag.
614
- if (!ctx.circular) {
615
- mod._sideEffectsStateGraph = moduleGraph;
616
- mod._sideEffectsStateValue = current;
617
- }
618
- return propagateLinearResult(linearAncestors, current, moduleGraph, ctx);
383
+ return result;
619
384
  };
620
385
 
621
386
  /**
@@ -886,6 +651,12 @@ class NormalModule extends Module {
886
651
  * @type {Source | null}
887
652
  */
888
653
  this._source = null;
654
+ // Set at build time; declared here so the instance shape is fixed at construction
655
+ /**
656
+ * @private
657
+ * @type {PreparsedAst | null}
658
+ */
659
+ this._ast = null;
889
660
  /**
890
661
  * @private
891
662
  * @type {Map<undefined | SourceType, number> | undefined}
@@ -920,8 +691,8 @@ class NormalModule extends Module {
920
691
  * graph slot keys the cached value to the `ModuleGraph` it was
921
692
  * computed against so stale values never leak across compilations
922
693
  * — a walk that targets a different graph just overwrites both
923
- * slots. Populated only for results computed without encountering
924
- * a circular connection (see `walkSideEffectsRecursive`).
694
+ * slots. Populated only for context-independent results (cycle-free
695
+ * or SCC-root modules; see `walkSideEffects`).
925
696
  * @type {ModuleGraph | undefined}
926
697
  */
927
698
  this._sideEffectsStateGraph = undefined;
@@ -1376,6 +1147,7 @@ class NormalModule extends Module {
1376
1147
  };
1377
1148
 
1378
1149
  Object.assign(loaderContext, options.loader);
1150
+ createLoaderContext(loaderContext);
1379
1151
 
1380
1152
  hooks.loader.call(
1381
1153
  /** @type {AnyLoaderContext} */
@@ -1673,6 +1445,9 @@ class NormalModule extends Module {
1673
1445
  buildDependencies.add(loader.loader);
1674
1446
  }
1675
1447
  buildInfo.cacheable = buildInfo.cacheable && result.cacheable;
1448
+ if (result.notCacheableReasons.length > 0) {
1449
+ buildInfo.notCacheableReasons = result.notCacheableReasons;
1450
+ }
1676
1451
  processResult(err, result.result);
1677
1452
  }
1678
1453
  );
@@ -1779,6 +1554,7 @@ class NormalModule extends Module {
1779
1554
  };
1780
1555
  this.buildInfo = {
1781
1556
  cacheable: false,
1557
+ notCacheableReasons: undefined,
1782
1558
  parsed: true,
1783
1559
  fileDependencies: undefined,
1784
1560
  contextDependencies: undefined,
@@ -1994,15 +1770,13 @@ class NormalModule extends Module {
1994
1770
  * @returns {ConnectionState} how this module should be connected to referencing modules when consumed for side-effects only
1995
1771
  */
1996
1772
  getSideEffectsConnectionState(moduleGraph) {
1997
- // Fresh per-walk context; re-entrant calls (e.g.
1773
+ // Each call owns its Tarjan bookkeeping; re-entrant calls (e.g.
1998
1774
  // `ConcatenatedModule.getSideEffectsConnectionState` delegating back
1999
- // through here) get their own and can't clobber the outer walk.
2000
- return walkSideEffectsRecursive(
1775
+ // through here) can't clobber the outer walk.
1776
+ return walkSideEffects(
2001
1777
  this,
2002
1778
  moduleGraph,
2003
- 0,
2004
- getHarmonyImportSideEffectDependency(),
2005
- { circular: false }
1779
+ getHarmonyImportSideEffectDependency()
2006
1780
  );
2007
1781
  }
2008
1782