Skip to content

Type serializer read/write contexts with positional tuples#21201

Merged
alexander-akait merged 16 commits into
mainfrom
claude/types-coverage-analysis-hwx7ir
Jun 17, 2026
Merged

Type serializer read/write contexts with positional tuples#21201
alexander-akait merged 16 commits into
mainfrom
claude/types-coverage-analysis-hwx7ir

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Jun 16, 2026

Copy link
Copy Markdown
Member

Summary

Types webpack's serializer read/write contexts (ObjectSerializerContext / ObjectDeserializerContext) with positional tuples, so each write/read is type-checked by slot across the dependency and cacheable-module classes: write(value: Head<T>) returns the context for Tail<T> (chain to advance), and reads advance via a no-allocation rest accessor. This catches wrong-order or wrong-type writes/reads at compile time.

Typing ProvideSharedDependency this way surfaced a real bug — its deserialize passed reads straight into the constructor, swapping version/request, and did an extra read() that misaligned the inherited loc fields. Fixed here with a round-trip test.

This relied on a generate-types fix (it previously dropped infer inside tuple extends clauses); that fix is now merged in webpack/tooling and this PR pins the tooling dependency to it, so types.d.ts regenerates cleanly and lint:special / lint:types-test pass.

What kind of change does this PR introduce?

feat (typing) plus a fix.

Did you add tests for your changes?

Yes — test/ProvideSharedDependency.unittest.js round-trips the dependency and asserts version/request survive serialization (fails on the old code, passes on the fix).

Does this PR introduce a breaking change?

No runtime or cache break: the serialize wire format is unchanged and CURRENT_VERSION is not bumped, so existing persistent caches stay valid. Type-only impact: the exported ObjectSerializerContext / ObjectDeserializerContext generics now constrain T to a tuple/array; default usage (no type argument) is unaffected, but third-party code that parameterized them with a non-array type (e.g. ObjectSerializerContext<string>) would need to update.

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) was used to design and implement the positional tuple typing, roll it out across the serializer/dependency/module classes, diagnose and fix the ProvideSharedDependency bug, and prepare the upstream tooling fix. All changes were reviewed and verified (tsc, targeted unit tests, and cache round-trip checks) before committing.

https://claude.ai/code/session_015uWCgLZJknabrCqSPGkSam

@changeset-bot

changeset-bot Bot commented Jun 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fa4b2c2

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

@linux-foundation-easycla

linux-foundation-easycla Bot commented Jun 16, 2026

Copy link
Copy Markdown

CLA Not Signed

@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

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

Install it locally:

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

@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.73196% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.74%. Comparing base (4fa6844) to head (fa4b2c2).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/dependencies/DllEntryDependency.js 0.00% 5 Missing ⚠️
...pendencies/ExternalModuleInitFragmentDependency.js 0.00% 5 Missing ⚠️
lib/serialization/ObjectMiddleware.js 83.33% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #21201      +/-   ##
==========================================
+ Coverage   92.25%   92.74%   +0.49%     
==========================================
  Files         591      591              
  Lines       64385    64289      -96     
  Branches    17858    17858              
==========================================
+ Hits        59397    59628     +231     
+ Misses       4988     4661     -327     
Flag Coverage Δ
css-parsing 28.71% <0.00%> (+0.05%) ⬆️
html5lib 31.17% <0.00%> (?)
integration 88.70% <95.46%> (-0.02%) ⬇️
test262 45.49% <0.00%> (+0.05%) ⬆️
unit 41.07% <4.94%> (+0.11%) ⬆️

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-hq

codspeed-hq Bot commented Jun 16, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 47.36%

⚠️ 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

⚡ 3 improved benchmarks
✅ 141 untouched benchmarks

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory benchmark "wasm-modules-async", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 330.4 KB 186.6 KB +77.07%
Memory benchmark "wasm-modules-sync", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 354.8 KB 256.4 KB +38.38%
Memory benchmark "asset-modules-bytes", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 322.5 KB 246.9 KB +30.59%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing claude/types-coverage-analysis-hwx7ir (fa4b2c2) with main (4fa6844)

Open in CodSpeed

alexander-akait and others added 16 commits June 17, 2026 16:48
generate-types (webpack/tooling) dropped `infer` in tuple element/rest
slots of conditional `extends` clauses, emitting invalid types.d.ts.
The patch renders extends-position tuples element-wise. Kept for
upstream contribution only; not wired into install. Refs #21191.
Preserves the positional ObjectSerializerContext/ObjectDeserializerContext
work (per-position write and read via a no-alloc `rest` accessor), with
built-in serializers and ConstDependency converted. Kept as a patch since
the generated types only validate after the tooling infer-in-tuple fix
ships.
ObjectSerializerContext<[A, B, C]> / ObjectDeserializerContext<[A, B, C]>
make each write/read position-checked: write chains and advances by
returning the next context; read advances via a no-alloc `rest` accessor.
Converts the 51 leaf dependency classes (fixed tuples where the shape is
fixed, open-array unions for looped serializers), the built-in JS-type
serializers, and ConstDependency. Base classes stay loose so subclass
overrides remain compatible. Requires the tooling infer-in-tuple fix to
regenerate types.d.ts.
Extends positional tuple typing (ObjectSerializerContext<[A,B,C]> /
ObjectDeserializerContext<[A,B,C]>) to the leaf module classes
(ContextModule, ExternalModule, RawModule, RawDataUrlModule, container/
sharing modules, CssModule, AsyncWasmModule, ...), the error classes, and
container/sharing dependencies. Module/NormalModule/InitFragment stay loose
as subclassed bases. ProvideSharedDependency left loose pending a separate
fix for its pre-existing serialize/deserialize mismatch.
Its serialize writes shareScope, name, request, version, eager, but the
static deserialize passed the reads straight into the constructor
(shareScope, name, version, request, eager), swapping version and request,
and did an extra read() that misaligned the inherited loc fields. Read into
named locals in wire order and reorder for the constructor; also apply
positional tuple typing so the slot order is type-checked. Adds a round-trip
unit test.
Point the tooling dependency at the merged commit that fixes infer in
tuple extends clauses, so types.d.ts regenerates upstream. Removes the
local patches/ workaround and its Project Overview entry.
Cover two serializers that used the destructured write/read style and
were missed earlier: RestoreProvidedData (fixed positional tuple) and
LazySet (open-array union, like SetObjectSerializer). Also syncs the
generated types.d.ts/yarn.lock after the rebase onto main.
@alexander-akait alexander-akait force-pushed the claude/types-coverage-analysis-hwx7ir branch from 5b4057d to fa4b2c2 Compare June 17, 2026 17:00
@github-actions

Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging claude/types-coverage-analysis-hwx7ir into main will be
99.35%
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.43%100%100%98.43%1618, 1937, 1944, 1952, 1974, 1977, 2917, 3396–3397, 3429, 4093, 4123, 4176–4177, 4181, 4186, 4202–4203, 4217–4218, 4223–4224, 4701, 4727, 514, 519, 5535, 5567, 5584, 5600, 5616, 5631, 5656–5657, 5659, 5987, 5992, 5998, 6001, 6013, 6015, 6019, 6035, 6050, 6082, 6136, 6160, 6274, 764–765
   Compiler.js99.56%100%100%99.56%1135–1136, 1144
   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.40%100%100%97.40%258, 395, 418, 420, 424, 433–434
   ContextReplacementPlugin.js100%100%100%100%
   DefinePlugin.js99%100%100%99%171–172, 188, 207, 281
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.28%100%100%98.28%425, 471
   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.50%100%100%98.50%1057, 1060, 445–449, 451, 597
   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, 3693, 3708, 3732
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.46%100%100%98.46%425, 434, 436, 440
   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.50%100%100%98.50%1285, 1290, 1350, 1364, 1426, 1435
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.85%100%100%98.85%106, 108
   ModuleGraph.js99.73%100%100%99.73%1005
   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%659
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.90%100%100%97.90%1240, 1243, 1260, 1277, 1524, 1558, 1574, 1661, 2017, 2316, 2321–2331, 419, 423, 577
   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.62%100%100%98.62%220, 224, 226, 419, 430, 891
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js99.17%100%100%99.17%176–177
   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.62%100%100%98.62%10, 119, 545, 577, 627, 897
   index.js99.72%100%100%99.72%184
   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%
   AssetModule.js100%100%100%100%
   AssetModulesPlugin.js97.32%100%100%97.32%281, 305, 308, 36, 360, 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.31%100%100%99.31%1439–1441, 1449, 274, 277, 282, 286
   defineConfig.js100%100%100%100%
   normalization.js99.01%100%100%99.01%191–192, 258, 273
   target.js100%100%100%100%
lib/container
   

@alexander-akait alexander-akait merged commit 907d23f into main Jun 17, 2026
65 of 66 checks passed
@alexander-akait alexander-akait deleted the claude/types-coverage-analysis-hwx7ir branch June 17, 2026 21:07
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