Skip to content

perf: walk side-effects iteratively without per-module generator allocation#21014

Merged
alexander-akait merged 4 commits into
mainfrom
perf/side-effects-iterative-walk
May 22, 2026
Merged

perf: walk side-effects iteratively without per-module generator allocation#21014
alexander-akait merged 4 commits into
mainfrom
perf/side-effects-iterative-walk

Conversation

@alexander-akait

Copy link
Copy Markdown
Member

The generator trampoline added in #20993 fixed the deep-chain stack
overflow (#20986) but allocated a fresh walkSideEffects generator
object for every NormalModule traversed by
getSideEffectsConnectionState, which CodSpeed flagged as a 22-48%
memory regression in three rebuild benchmarks.

Replace the generator with an explicit parallel-array frame stack
(modStack / depsStack / indexStack / currentStack) so each
descent only grows fixed-size arrays instead of allocating an iterator
object. A short-circuit fast path (sideEffectsFastPath) handles the
factoryMeta / buildMeta / re-entry checks without ever touching the
frame stack — the common case (most modules) returns in a couple of
property reads with zero allocation.

The 20000-module chain in NormalModule.unittest.js still completes
without overflowing the stack; a new diamond test confirms branching
deps still aggregate correctly. A local microbench of the existing
chain fixture shows the walk is ~2-3x faster than the generator form
on chains of 10-20000 modules.

Copilot AI review requested due to automatic review settings May 21, 2026 20:17
@changeset-bot

changeset-bot Bot commented May 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18ff7f8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
webpack Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

This PR is packaged and the instant preview is available (c755747).

Install it locally:

  • npm
npm i -D webpack@https://pkg.pr.new/webpack@c755747
  • yarn
yarn add -D webpack@https://pkg.pr.new/webpack@c755747
  • pnpm
pnpm add -D webpack@https://pkg.pr.new/webpack@c755747

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes NormalModule#getSideEffectsConnectionState by replacing the per-module generator allocation (introduced to avoid deep recursion stack overflows) with an explicit iterative traversal using parallel-array stacks. This keeps the walk stack-safe on deep chains while reducing allocations and improving rebuild performance.

Changes:

  • Replaced the generator-trampoline side-effects walk with an allocation-light iterative loop using explicit stacks.
  • Added a fast-path helper to resolve side-effects state without descending when it can be determined from metadata / re-entry checks.
  • Extended unit tests with a branching (“diamond”) dependency case to validate correct aggregation across multiple deps.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
lib/NormalModule.js Reworks side-effects traversal to an iterative stack-based algorithm with a metadata-based fast path.
test/NormalModule.unittest.js Adds a branching-deps test to validate correct state aggregation and flag cleanup.
.changeset/iterative-side-effects-walk.md Adds a patch changeset documenting the perf-focused rewrite.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov

codecov Bot commented May 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.12195% with 51 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.56%. Comparing base (b3893ec) to head (18ff7f8).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/NormalModule.js 75.12% 51 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #21014      +/-   ##
==========================================
- Coverage   91.63%   91.56%   -0.08%     
==========================================
  Files         573      573              
  Lines       59277    59460     +183     
  Branches    16012    16054      +42     
==========================================
+ Hits        54321    54443     +122     
- Misses       4956     5017      +61     
Flag Coverage Δ
integration 89.47% <45.36%> (-0.18%) ⬇️
test262 45.31% <39.51%> (-0.09%) ⬇️
unit 37.95% <65.85%> (+0.09%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@alexander-akait alexander-akait force-pushed the perf/side-effects-iterative-walk branch from 2e8d002 to aa20f65 Compare May 21, 2026 20:54
@codspeed-hq

codspeed-hq Bot commented May 21, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 52.18%

⚡ 2 improved benchmarks
❌ 7 regressed benchmarks
✅ 135 untouched benchmarks
⏩ 72 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory benchmark "side-effects-reexport", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 402.4 KB 1,033.2 KB -61.05%
Memory benchmark "asset-modules-source", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 400.5 KB 3,718.4 KB -89.23%
Memory benchmark "concatenate-modules", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 161.9 KB 486.4 KB -66.71%
Memory benchmark "many-chunks-esm", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 170 KB 253.1 KB -32.84%
Memory benchmark "concatenate-modules", scenario '{"name":"mode-development","mode":"development"}' 1,116.8 KB 784.8 KB +42.29%
Memory benchmark "asset-modules-bytes", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 133.6 KB 323.4 KB -58.7%
Memory benchmark "future-defaults", scenario '{"name":"mode-production","mode":"production"}' 11.4 MB 8.4 MB +35.55%
Memory benchmark "many-chunks-commonjs", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 185.9 KB 446.6 KB -58.38%
Memory benchmark "cache-filesystem", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 355.1 KB 844.8 KB -57.97%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing perf/side-effects-iterative-walk (18ff7f8) with main (b3893ec)

Open in CodSpeed

Footnotes

  1. 72 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Copilot AI review requested due to automatic review settings May 21, 2026 21:17
@alexander-akait alexander-akait force-pushed the perf/side-effects-iterative-walk branch from aa20f65 to 52746f1 Compare May 21, 2026 21:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread lib/NormalModule.js Outdated
Comment on lines +238 to +244
if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
currentStack[top] = ModuleGraphConnection.addConnectionStates(
currentStack[top],
state
);
}
indexStack[top]++;
Comment thread lib/NormalModule.js
descended = true;
break;
}
} else {
Three additive optimizations to the cached walker:

- Inline the fast-path checks into both recursive and iterative
  walkers, saving one V8 stack frame per descent. The standalone
  `sideEffectsFastPath` helper is removed (only ever used by the
  walkers, now inlined).
- Hoist `getHarmonyImportSideEffectDependency()` to one resolution at
  the public entry; threaded into the recursive call as a parameter.
- Replace the per-frame `_sideEffectsCircularSeen` save/restore with a
  single per-walk flag reset only at the public entry. A cycle
  anywhere in the walk inhibits caching for the rest of that walk —
  strictly conservative vs. the previous subtree-scoped tracking, but
  cycle-free builds (the common case) cache identically.
- Add cache lookup and cache store to the iterative form so deep-chain
  walks also benefit from memoization, and inline its fast-path
  checks.

Latest microbench (best of 7, fresh chain per call where applicable):

  First-walk only (cold cache):
    chain    BEFORE     NOW
     10      311 ns     293 ns          (faster than BEFORE)
     100     99 ns      96 ns           (faster than BEFORE)
     1000   127 ns      136 ns
     5000   123 ns      485 ns          (iterative tail engaged)

  Repeated queries (SideEffectsFlagPlugin access pattern):
    chain    BEFORE        NOW
     10      0.03 ms       0.08 ms
     100     0.13 ms       0.06 ms      2.2x
     1000   14.34 ms       0.42 ms      34x
     5000  694.30 ms       1.90 ms      365x
@alexander-akait alexander-akait force-pushed the perf/side-effects-iterative-walk branch from 52746f1 to 9a593fa Compare May 21, 2026 21:33
Copilot AI review requested due to automatic review settings May 21, 2026 21:38
A purely linear chain of side-effect-free imports — module A imports
B imports C imports ... — is the worst case for stack-frame-per-module
walking. It is also the pattern that triggered #20986.

walkSideEffectsRecursive now peels off linear-chain heads inside a
single frame. Each iteration of the inner loop:
  - runs the cache check + fast-path checks against the current
    module,
  - if the module is a linear-chain head (exactly one
    HarmonyImportSideEffectDependency to another NormalModule), pushes
    it onto a per-walk ancestor stack and continues with the referenced
    module,
  - if not, breaks out to the existing general for-loop walk.

The chain's tail returns a state which propagateLinearResult walks
back up the ancestor stack, applying the same aggregation rules the
recursive call would have applied (bailout, CIRCULAR filtering,
caching).

Net effect: walks that were strictly linear cost one V8 frame total
no matter how deep, and never hit walkSideEffectsIterative. The depth
limit only applies to genuinely branching graphs where each level
truly needs its own frame.

Microbench (median, fresh chain per call, no cache reuse):

  chain    BEFORE     prev (v2)     NOW (v3)
   10      309 ns     293 ns        292 ns
   100     143 ns     96 ns         127 ns
   1000    114 ns     136 ns        123 ns
   5000    123 ns     485 ns        146 ns

The chain=5000 regression vs. BEFORE is gone — the linear-chain
fast path keeps it within run-to-run noise of the recursive baseline.

Repeated queries (SideEffectsFlagPlugin pattern, chain=5000):
  BEFORE: 676.64 ms
  NOW:      1.83 ms   (370x faster)
@alexander-akait alexander-akait force-pushed the perf/side-effects-iterative-walk branch from 67f2ef5 to b669589 Compare May 21, 2026 21:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comment thread lib/NormalModule.js
Comment on lines +210 to +218
if (state === true) {
recordSideEffectsBailout(topMod, moduleGraph, dep);
topMod._isEvaluatingSideEffects = false;
modStack.pop();
depsStack.pop();
indexStack.pop();
currentStack.pop();
pending = true;
continue;
Comment thread lib/NormalModule.js
Comment on lines +836 to 848
* Memoizes the result of `getSideEffectsConnectionState`. The
* graph slot keys the cached value to the `ModuleGraph` it was
* computed against so stale values never leak across compilations
* — a walk that targets a different graph just overwrites both
* slots. Populated only for results computed without encountering
* a circular connection (see `walkSideEffectsRecursive`).
* @type {ModuleGraph | undefined}
*/
this._sideEffectsStateGraph = undefined;
/** @type {ConnectionState | undefined} */
this._sideEffectsStateValue = undefined;
/**
* @private
Comment thread lib/NormalModule.js
Comment on lines +475 to +482
// Non-linear walk. Each genuine recursive call costs one V8 frame, so
// honour the depth limit here.
if (depth >= SIDE_EFFECTS_RECURSION_LIMIT) {
return propagateLinearResult(
linearAncestors,
walkSideEffectsIterative(mod, moduleGraph),
moduleGraph
);
Comment on lines +432 to +436
it("propagates a deep-chain bailout all the way back to the root", () => {
// 5000 modules is far beyond what the recursive walker would walk
// using V8 stack frames; the linear-chain peeling code path must
// still propagate a bailout deep in the tail back to module 0.
const { modules, moduleGraph } = buildChain(5000);
The previous linear-chain optimization only fired when a module had
exactly one entry in `dependencies` — but a real ESM module compiled
by webpack has the `HarmonyImportSideEffectDependency` *plus* an
`HarmonyExportSpecifierDependency` per `export` and a `ConstDependency`
per replaced expression. With the strict `length === 1` check the
1300-module cyclic chain (the canonical #20986 repro) fell through to
the general for-loop walk and overflowed V8's stack at ~1300 frames
again on Node 22+.

Loosen the linear-chain detection to "exactly one `SideEffectDep`
among any number of deps whose `getModuleEvaluationSideEffectsState`
returns `false`/`CIRCULAR_CONNECTION`". The walker now processes the
module's non-recursive deps in their declared order — bailing out
correctly with the first dep whose state is `true`, aggregating
non-`false` states into `nonRecursiveCurrent` — and only attempts the
linear tail-call when:

  - at most one `SideEffectDep` was seen,
  - no non-recursive dep triggered a bailout,
  - `nonRecursiveCurrent` stayed at `false` (otherwise the
    "ancestor's current = chain state" propagation rule no longer
    holds and we fall back to the general walk).

Verified on the actual #20986 repro (1300-module cyclic chain):

    AFTER  (#20993 generator trampoline)  ~12.3 s
    NOW    (this branch)                   ~6.5 s    (~1.9x faster)

  Larger chains (N >= 3000) hit pre-existing stack overflows in
  `ModuleConcatenationPlugin._tryToAdd` and
  `SideEffectsFlagPlugin.optimizeIncomingConnections` that are out of
  scope here — both branches behave identically there.

Adds a regression test that builds a 5000-module cyclic chain whose
modules have the same `[SideEffectDep, ConstDependency, ConstDependency]`
dependency shape as the real repro.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread lib/NormalModule.js
Comment on lines +205 to +218
if (pending !== undefined) {
const state = pending;
pending = undefined;
const dep = deps[index];

if (state === true) {
recordSideEffectsBailout(topMod, moduleGraph, dep);
topMod._isEvaluatingSideEffects = false;
modStack.pop();
depsStack.pop();
indexStack.pop();
currentStack.pop();
pending = true;
continue;
Comment thread lib/NormalModule.js
Comment on lines +367 to +374
ancestor._isEvaluatingSideEffects = false;
const dep = ancestor.dependencies[0];

if (state === true) {
recordSideEffectsBailout(ancestor, moduleGraph, dep);
// `true` is monotonic — safe to cache regardless of cycle status.
ancestor._sideEffectsStateGraph = moduleGraph;
ancestor._sideEffectsStateValue = true;
Three correctness fixes + a leak cleanup + a coverage gap, all flagged
by Copilot on PR #21014:

1. propagateLinearResult was using `ancestor.dependencies[0]` as the
   bailout dep, but a module qualifying for the linear-chain fast path
   can have non-recursive deps (ConstDependency, HarmonyExport*) before
   its single HarmonyImportSideEffectDependency. The recorded bailout
   would then point at the wrong dep type / location. Push pairs of
   `(mod, linearDep)` onto `linearAncestors` and pop both in the
   propagation walk so the bailout always references the actual
   SideEffectDep that triggered the descent.

2. The iterative walker's `pending === true` propagation path popped
   each parent frame without writing `_sideEffectsStateGraph` /
   `_sideEffectsStateValue`, even though `true` is monotonic and is
   already memoized in the sibling `state === true` branch. Memoize
   `true` here too so deep-tree bailouts don't re-walk on subsequent
   queries.

3. `cleanupForCache` now clears `_sideEffectsStateGraph` and
   `_sideEffectsStateValue`. Otherwise a long-lived NormalModule
   strong-references the ModuleGraph it was last walked against,
   keeping the entire Compilation alive across watch-mode rebuilds for
   modules that are never re-queried with a fresh ModuleGraph.

4. Adds a regression test that builds a 2500-module *non-linear*
   graph (each module has two SideEffectDeps so the linear-chain fast
   path can't apply). The walker recurses one V8 frame per module and
   must cross `SIDE_EFFECTS_RECURSION_LIMIT` into the iterative
   fallback — exercising the path that was previously only covered by
   indirect tests.
@github-actions

Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging perf/side-effects-iterative-walk into main will be
98.97%
Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
bin
   webpack.js98.77%100%100%98.77%91
examples
   build-common.js100%100%100%100%
   buildAll.js100%100%100%100%
   examples.js100%100%100%100%
   template-common.js98.21%100%100%98.21%72
examples/custom-javascript-parser
   test.filter.js100%100%100%100%
examples/custom-javascript-parser/internals
   acorn-parse.js100%100%100%100%
   meriyah-parse.js100%100%100%100%
   oxc-parse.js91.30%100%100%91.30%140, 142–143, 145, 147, 153–154, 161, 168, 90
examples/markdown
   webpack.config.mjs100%100%100%100%
examples/typescript
   test.filter.js100%100%100%100%
examples/typescript-non-erasable
   test.filter.js50%100%100%50%5
examples/virtual-modules
   test.filter.js100%100%100%100%
examples/wasm-bindgen-esm
   test.filter.js100%100%100%100%
examples/wasm-complex
   test.filter.js100%100%100%100%
examples/wasm-simple
   test.filter.js100%100%100%100%
examples/wasm-simple-source-phase
   test.filter.js100%100%100%100%
lib
   APIPlugin.js100%100%100%100%
   AsyncDependenciesBlock.js100%100%100%100%
   AutomaticPrefetchPlugin.js100%100%100%100%
   BannerPlugin.js100%100%100%100%
   Cache.js98.21%100%100%98.21%101
   CacheFacade.js100%100%100%100%
   Chunk.js99.72%100%100%99.72%39
   ChunkGraph.js100%100%100%100%
   ChunkGroup.js100%100%100%100%
   ChunkTemplate.js100%100%100%100%
   CleanPlugin.js99.15%100%100%99.15%206, 226
   CodeGenerationResults.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.45%100%100%98.45%1572, 1868, 1875, 1883, 1905, 2801, 3226, 3888, 3917, 3970–3971, 3975, 3980, 3996–3997, 4011–4012, 4017–4018, 4495, 4521, 511, 516, 5229, 5261, 5278, 5294, 5310, 5325, 5350–5351, 5353, 5681, 5686, 5692, 5695, 5707, 5709, 5713, 5729, 5744, 5776, 5830, 5854, 5968, 730–731
   Compiler.js99.55%100%100%99.55%1116–1117, 1125
   ConcatenationScope.js98.59%100%100%98.59%189
   ConditionalInitFragment.js100%100%100%100%
   ConstPlugin.js100%100%100%100%
   ContextExclusionPlugin.js100%100%100%100%
   ContextModule.js100%100%100%100%
   ContextModuleFactory.js97.75%100%100%97.75%258, 393, 418, 443, 447, 458
   ContextReplacementPlugin.js100%100%100%100%
   DefinePlugin.js98.92%100%100%98.92%158–159, 175, 194, 268
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.20%100%100%98.20%379, 425
   DependencyTemplate.js100%100%100%100%
   DependencyTemplates.js100%100%100%100%
   DotenvPlugin.js98.41%100%100%98.41%378, 391–392
   DynamicEntryPlugin.js100%100%100%100%
   EntryOptionPlugin.js100%100%100%100%
   EntryPlugin.js100%100%100%100%
   Entrypoint.js100%100%100%100%
   EnvironmentPlugin.js97.14%100%100%97.14%49
   ErrorHelpers.js100%100%100%100%
   EvalDevToolModulePlugin.js100%100%100%100%
   EvalSourceMapDevToolPlugin.js100%100%100%100%
   ExportsInfo.js100%100%100%100%
   ExportsInfoApiPlugin.js100%100%100%100%
   ExternalModule.js98.97%100%100%98.97%425–429, 577
   ExternalModuleFactoryPlugin.js100%100%100%100%
   ExternalsPlugin.js100%100%100%100%
   FileSystemInfo.js99.50%100%100%99.50%182, 2252–2253, 2256, 2267, 2278, 2289, 278, 3694, 3709, 3733
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.74%100%100%98.74%399, 401, 405
   FlagDependencyUsagePlugin.js100%100%100%100%
   FlagEntryExportAsUsedPlugin.js100%100%100%100%
   Generator.js100%100%100%100%
   HotModuleReplacementPlugin.js100%100%100%100%
   HotUpdateChunk.js100%100%100%100%
   IgnorePlugin.js100%100%100%100%
   IgnoreWarningsPlugin.js100%100%100%100%
   InitFragment.js100%100%100%100%
   JavascriptMetaInfoPlugin.js100%100%100%100%
   LibraryTemplatePlugin.js100%100%100%100%
   LoaderOptionsPlugin.js100%100%100%100%
   LoaderTargetPlugin.js100%100%100%100%
   MainTemplate.js100%100%100%100%
   ManifestPlugin.js100%100%100%100%
   Module.js98.50%100%100%98.50%1305, 1310, 1371, 1385, 1447, 1456
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.85%100%100%98.85%106, 108
   ModuleGraph.js99.73%100%100%99.73%1004
   ModuleGraphConnection.js100%100%100%100%
   ModuleInfoHeaderPlugin.js100%100%100%100%
   ModuleNotFoundError.js100%100%100%100%
   ModuleProfile.js100%100%100%100%
   ModuleSourceTypeConstants.js100%100%100%100%
   ModuleTemplate.js100%100%100%100%
   ModuleTypeConstants.js100%100%100%100%
   MultiCompiler.js99.69%100%100%99.69%645
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js98.11%100%100%98.11%1211, 1214, 1231, 1248, 1489, 1523, 1539, 1626, 2249, 2254–2264, 569
   NormalModuleFactory.js99.47%100%100%99.47%1083, 1392, 486, 498
   NormalModuleReplacementPlugin.js100%100%100%100%
   NullFactory.js100%100%100%100%
   OptimizationStages.js100%100%100%100%
   OptionsApply.js100%100%100%100%
   Parser.js100%100%100%100%
   PlatformPlugin.js100%100%100%100%
   PrefetchPlugin.js100%100%100%100%
   ProgressPlugin.js98.85%100%100%98.85%519–520, 525, 527, 591
   ProvidePlugin.js100%100%100%100%
   RawModule.js100%100%100%100%
   RecordIdsPlugin.js100%100%100%100%
   RequestShortener.js100%100%100%100%
   ResolverFactory.js100%100%100%100%
   RuntimeGlobals.js100%100%100%100%
   RuntimeModule.js100%100%100%100%
   RuntimePlugin.js100%100%100%100%
   RuntimeTemplate.js100%100%100%100%
   SelfModuleFactory.js100%100%100%100%
   SingleEntryPlugin.js100%100%100%100%
   SourceMapDevToolModuleOptionsPlugin.js100%100%100%100%
   SourceMapDevToolPlugin.js98.59%100%100%98.59%218, 222, 224, 398, 409, 811
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js98.86%100%100%98.86%136–137
   UseStrictPlugin.js100%100%100%100%
   WarnCaseSensitiveModulesPlugin.js100%100%100%100%
   WarnDeprecatedOptionPlugin.js100%100%100%100%
   WarnNoModeSetPlugin.js100%100%100%100%
   WatchIgnorePlugin.js100%100%100%100%
   Watching.js100%100%100%100%
   WebpackError.js100%100%100%100%
   WebpackIsIncludedPlugin.js100%100%100%100%
   WebpackOptionsApply.js100%100%100%100%
   WebpackOptionsDefaulter.js100%100%100%100%
   buildChunkGraph.js99.87%100%100%99.87%325
   cli.js98.46%100%100%98.46%10, 119, 471, 503, 545, 815
   index.js99.72%100%100%99.72%165
   validateSchema.js94.67%100%100%94.67%100, 87, 89, 98
   webpack.js96.33%100%100%96.33%10, 198, 220, 222
lib/asset
   AssetBytesGenerator.js100%100%100%100%
   AssetBytesParser.js100%100%100%100%
   AssetGenerator.js100%100%100%100%
   AssetModulesPlugin.js97.32%100%100%97.32%283, 307, 310, 36, 362, 41
   AssetParser.js100%100%100%100%
   AssetSourceGenerator.js100%100%100%100%
   AssetSourceParser.js100%100%100%100%
   RawDataUrlModule.js100%100%100%100%
lib/async-modules
   AsyncModuleHelpers.js100%100%100%100%
   AwaitDependenciesInitFragment.js100%100%100%100%
   InferAsyncModulesPlugin.js100%100%100%100%
lib/cache
   AddBuildDependenciesPlugin.js100%100%100%100%
   AddManagedPathsPlugin.js100%100%100%100%
   IdleFileCachePlugin.js97.92%100%100%97.92%71, 83, 91
   MemoryCachePlugin.js95.83%100%100%95.83%33
   MemoryWithGcCachePlugin.js93.15%100%100%93.15%106, 113–114, 122, 89
   PackFileCacheStrategy.js96.40%100%100%96.40%1250, 1350, 1354, 1416, 628, 647, 657–659, 661, 677–678, 683, 686, 688, 693, 698, 722, 728, 762, 768, 774, 779, 790, 799, 804–805, 807, 824, 830–831, 833
   ResolverCachePlugin.js100%100%100%100%
   getLazyHashedEtag.js100%100%100%100%
   mergeEtags.js100%100%100%100%
lib/config
   browserslistTargetHandler.js100%100%100%100%
   defaults.js99.29%100%100%99.29%1411–1413, 1421, 271, 274, 279, 283
   normalization.js99%100%100%99%191–192, 258, 273
   target.js100%100%100%100%
lib/container
   ContainerEntryDependency.js100%100%100%100%
   ContainerEntryModule.js100%100%100%100%
   ContainerEntryModuleFactory.js100%100%100%100%
   ContainerExposedDependency.js100%100%100%100%
   ContainerPlugin.js100%100%100%100%
   ContainerReferencePlugin.js100%100%100%100%
   FallbackDependency.js100%100%100%100%
   

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@alexander-akait alexander-akait merged commit c755747 into main May 22, 2026
59 of 62 checks passed
@alexander-akait alexander-akait deleted the perf/side-effects-iterative-walk branch May 22, 2026 09:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants