Skip to content

refactor(module): add internal parser/generator lifecycle for incremental rebuilds - #21555

Merged
alexander-akait merged 9 commits into
mainfrom
refactor/module-parser-lifecycle
Jul 31, 2026
Merged

alexander-akait merged 9 commits into
mainfrom
refactor/module-parser-lifecycle

Conversation

@bjohansebas

@bjohansebas bjohansebas commented Jul 30, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds an internal parser/generator lifecycle to Module/NormalModule (_cleanupParserForCache releases the parser so it does not retain the previous compilation; _restoreParserAndGenerator re-acquires both from the factory so the new compilation's plugin hooks apply), and makes AsyncQueue.invalidate tolerate items absent from the current run. No behavior change; third PR of the incremental-rebuilds series (stacked on #21553, extracted from perf/incremental-rebuild).

What kind of change does this PR introduce?

refactor

Did you add tests for your changes?

Yes, new cases in test/NormalModule.unittest.js and test/AsyncQueue.unittest.js.

Does this PR introduce a breaking change?

No.

If relevant, what needs to be documented once your changes are merged or what have you already documented?

n/a

Use of AI

AI (Claude Code) was used to extract this change from my working branch, adapt it onto current main, and draft the unit tests; I reviewed and validated everything locally.


Note

Low Risk
Internal hooks and a defensive guard in AsyncQueue with no current call sites in this diff; behavior change is limited to invalidate on absent keys, which is explicitly tested.

Overview
Prepares incremental rebuilds by introducing internal lifecycle hooks on Module / NormalModule for factory-derived parser and generator instances.

_cleanupParserForCache drops the cached parser so it does not retain the previous compilation. _restoreParserAndGenerator re-fetches parser and generator from NormalModuleFactory so the new compilation’s plugin hooks apply. Base Module defines no-op stubs; NormalModule implements them (parser-only cleanup vs full restore). This PR does not wire these hooks into compilation yet—they are scaffolding for the incremental-rebuild stack.

AsyncQueue.invalidate now returns immediately when there is no entry for the key (e.g. invalidating modules from a persisted graph that were not added in the current run), instead of assuming an entry exists.

Unit tests cover the NormalModule lifecycle and the no-op invalidate path.

Reviewed by Cursor Bugbot for commit 895ffe0. Bugbot is set up for automated code reviews on this repo. Configure here.

@changeset-bot

changeset-bot Bot commented Jul 30, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 895ffe0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@github-actions

github-actions Bot commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

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

Install it locally:

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

@codecov

codecov Bot commented Jul 30, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.77778% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.80%. Comparing base (888d134) to head (895ffe0).

Files with missing lines Patch % Lines
lib/Module.js 0.00% 2 Missing ⚠️
Additional details and impacted files
@@                         Coverage Diff                          @@
##           refactor/exports-info-reset-apis   #21555      +/-   ##
====================================================================
- Coverage                             93.80%   93.80%   -0.01%     
====================================================================
  Files                                   622      622              
  Lines                                 74500    74508       +8     
  Branches                              21616    21617       +1     
====================================================================
+ Hits                                  69885    69889       +4     
- Misses                                 4615     4619       +4     
Flag Coverage Δ
css-parsing 25.39% <0.00%> (-0.01%) ⬇️
html5lib 26.76% <0.00%> (-0.01%) ⬇️
integration 89.42% <22.22%> (-0.02%) ⬇️
test262 42.93% <0.00%> (-0.01%) ⬇️
unit 47.39% <77.77%> (+<0.01%) ⬆️

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

☔ View full report in Codecov by Harness.
📢 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.

@codspeed

codspeed Bot commented Jul 30, 2026 •

Copy link
Copy Markdown

Merging this PR will degrade performance by 13.24%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
❌ 1 regressed benchmark
✅ 218 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ Memory benchmark "asset-modules-resource", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 660.4 KB 1,242.7 KB -46.86%
⚡ Memory benchmark "asset-modules-inline", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 395.3 KB 279.1 KB +41.65%

Tip

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


Comparing refactor/module-parser-lifecycle (895ffe0) with refactor/exports-info-reset-apis (888d134)

Open in CodSpeed

…l rebuilds

Reset provide-side and use-side export info to the undetermined state so
FlagDependencyExports/FlagDependencyUsage can recompute them against a
persisted module graph. No behavior change.
…exports

Mirror setHasUseInfo: _resetUseInfo recurses into an owned nested
exportsInfo and _resetUsedExports follows the redirect target, so no
stale usage survives a use-only reset.
…ale inlined flag

Reset an owned nested exportsInfo in place instead of discarding it (its
use state must survive a provide-only reset), and clear the
_hasInlinedExports fast-path flag when use info is reset.
@bjohansebas
bjohansebas force-pushed the refactor/module-parser-lifecycle branch from a6df7b2 to e93bb4d Compare July 30, 2026 19:41
…s info

After a provide reset the nested exports are back to undefined, and
FlagDependencyExports only upgrades provided from false/null, so the
module-level re-init must reach nested exports (mirrors setHasUseInfo).
The redirect points into another module's exports info; the global
incremental reset loop already resets it via its own module, so
following it wiped foreign state (and double-reset shared targets).
Assert use-state resets through the public getUsed/getUsedName API
instead of private fields, and cast the setTarget/canInlineProvide
fixtures.
…ntal rebuilds

_cleanupParserForCache releases the parser between rebuilds so it does
not retain the previous compilation; _restoreParserAndGenerator
re-acquires both from the factory so the new compilation's plugin hooks
apply. AsyncQueue.invalidate now tolerates items absent from the
current run. No behavior change.
@bjohansebas
bjohansebas force-pushed the refactor/module-parser-lifecycle branch from e93bb4d to c121b43 Compare July 30, 2026 20:37
@github-actions

Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging refactor/module-parser-lifecycle into refactor/exports-info-reset-apis will be
99.32%
Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
bin
   webpack.js98.82%100%100%98.82%103
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.js100%100%100%100%
examples/markdown
   webpack.config.mjs100%100%100%100%
examples/module-federation
   test.filter.js100%100%100%100%
examples/reexport-components
   test.filter.js100%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-emscripten
   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%
   CircularModulesPlugin.js98.81%100%100%98.81%136
   CleanPlugin.js99.13%100%100%99.13%214, 234
   CodeGenerationResults.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.42%100%100%98.42%1648, 1967, 1974, 1982, 2004, 2007, 2946, 3425–3426, 3458, 4162, 4192, 4245–4246, 4250, 4255, 4271–4272, 4286–4287, 4292–4293, 4773, 4799, 527, 532, 5607, 5639, 5656, 5672, 5688, 5703, 5728–5729, 5731, 6061, 6066, 6072, 6075, 6082, 6094, 6096, 6100, 6116, 6131, 6163, 6217, 6241, 6356, 778–779
   Compiler.js99.56%100%100%99.56%1159–1160, 1168
   ConcatenationScope.js98.65%100%100%98.65%195
   ConditionalInitFragment.js100%100%100%100%
   ConstPlugin.js100%100%100%100%
   ContextExclusionPlugin.js100%100%100%100%
   ContextModule.js99.88%100%100%99.88%1461
   ContextModuleFactory.js97.20%100%100%97.20%266, 435, 456, 461, 501, 512, 514, 518, 527–528
   ContextReplacementPlugin.js100%100%100%100%
   DefinePlugin.js99.08%100%100%99.08%1080, 176–177, 193, 212, 286
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.51%100%100%98.51%479, 525
   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.65%100%100%98.65%1202, 1205, 514–518, 520, 666
   ExternalModuleFactoryPlugin.js100%100%100%100%
   ExternalsPlugin.js100%100%100%100%
   FileSystemInfo.js99.16%100%100%99.16%1267, 1269–1274, 1281, 1284, 182, 2502–2503, 2506, 2517, 2528, 2539, 280, 3976, 3991, 4015
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.21%100%100%98.21%448, 457, 460, 464, 476
   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%
   LazyBarrel.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.51%100%100%98.51%1303, 1308, 1368, 1382, 1444, 1453
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.90%100%100%98.90%111, 113
   ModuleGraph.js99.78%100%100%99.78%1170
   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.70%100%100%99.70%663
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.98%100%100%97.98%1020, 1023, 1040, 1057, 1305, 1339, 1355, 1803, 2100, 2105–2115, 34
   NormalModuleFactory.js98.72%100%100%98.72%1123, 1391, 1402, 1412, 1463–1465, 1472, 526, 538
   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.js99.80%100%100%99.80%691
   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.63%100%100%98.63%220, 224, 226, 420, 431, 890
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js99.43%100%100%99.43%308–309
   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%371
   cli.js98.63%100%100%98.63%10, 119, 549, 581, 631, 905
   index.js99.73%100%100%99.73%184
   validateSchema.js94.67%100%100%94.67%100, 87, 89, 98
   webpack.js97.10%100%100%97.10%10, 263, 285, 287
lib/asset
   AssetBytesGenerator.js100%100%100%100%
   AssetBytesParser.js100%100%100%100%
   AssetGenerator.js100%100%100%100%
   AssetModule.js100%100%100%100%
   AssetModulesPlugin.js97.95%100%100%97.95%295, 319, 322, 42, 452, 47
   AssetParser.js100%100%100%100%
   AssetSourceGenerator.js100%100%100%100%
   AssetSourceParser.js100%100%100%100%
   RawDataUrlModule.js100%100%100%100%
   WebManifestGenerator.js100%100%100%100%
   WebManifestParser.js100%100%100%100%
lib/async-modules
   AsyncModuleHelpers.js100%100%100%100%
   AwaitDependenciesInitFragment.js100%100%100%100%
   InferAsyncModulesPlugin.js100%100%100%100%
   isGeneratorLowered.js100%100%100%100%
lib/bun
   BunTargetPlugin.js100%100%100%100%
lib/cache
   AddBuildDependenciesPlugin.js100%100%100%100%
   AddManagedPathsPlugin.js100%100%100%100%
   IdleFileCachePlugin.js97.92%100%100%97.92%75, 87, 95
   MemoryCachePlugin.js95.83%100%100%95.83%33
   MemoryWithGcCachePlugin.js93.15%100%100%93.15%107, 114–115, 123, 90
   PackFileCacheStrategy.js96.52%100%100%96.52%1310, 1410, 1414, 1476, 1712, 1796, 1819, 1851, 675, 694, 704–706, 708, 724–725, 730, 733, 735, 740, 745, 770, 776, 810, 816, 822, 827, 838, 847, 852–853, 855, 872, 878–879, 881
   ResolverCachePlugin.js100%100%100%100%
   getLazyHashedEtag.js1

Base automatically changed from refactor/exports-info-reset-apis to main July 31, 2026 09:29
@alexander-akait
alexander-akait merged commit afd3006 into main Jul 31, 2026
62 of 63 checks passed
@alexander-akait
alexander-akait deleted the refactor/module-parser-lifecycle branch July 31, 2026 09:30
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.

3 participants