Skip to content

perf: re-encode the HTML AST as struct-of-arrays behind a path-based visitor API#21331

Merged
alexander-akait merged 9 commits into
mainfrom
perf/html-parser-soa-ast
Jul 3, 2026
Merged

perf: re-encode the HTML AST as struct-of-arrays behind a path-based visitor API#21331
alexander-akait merged 9 commits into
mainfrom
perf/html-parser-soa-ast

Conversation

@alexander-akait

Copy link
Copy Markdown
Member

Summary

The experimental HTML parser held one object per AST node plus a children array per parent, dominating parse-time heap. Nodes and attributes now live in parallel typed-array columns (an integer id per node/attribute) behind an accessor, cutting retained AST memory 57–68% (45.2→19.4 MB full tree, 30.9→9.9 MB under HtmlParser's skip config on a 2.4 MB document) and parse+walk CPU ~17%, measured interleaved against main. Visitors (HTML and CSS) now receive a single Babel-style path argument (one reused object, no per-node allocation), and the HTML walk is iterative over the link columns, fixing a RangeError stack overflow on ~100k-deep nesting; trees serialize byte-identically to the previous implementation across the full html5lib corpus (8389 inputs, all skip combinations and fragment modes). Refs #21323.

What kind of change does this PR introduce?

perf

Did you add tests for your changes?

Yes — test/buildHtmlAst.unittest.js and test/html5lib.spectest.js now exercise the new accessor/path API (including a materialization helper that reads every accessor), and the existing conformance, skip-parity, and configCases/{html,css} suites cover the representation change.

Does this PR introduce a breaking change?

No — the visitor/accessor API of the experimental HTML/CSS parsers is webpack-internal, and build output is unchanged.

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

n/a

Use of AI

This PR was implemented with Claude Code under my direction: it performed the mechanical SoA conversion, API migration, and benchmarking, gated by a differential harness asserting byte-identical serialization against the previous implementation over the html5lib corpus; I reviewed the design and the resulting diff.


Generated by Claude Code

One AST node is now an integer id into parallel typed-array columns (type,
flags, offsets, parent/firstChild/lastChild/nextSibling links) plus two side
arrays for the string payload and attribute lists — no per-node object and no
per-parent children array. All consumer reads go through a new accessor `A`
(the same seam as the CSS parser's `A`), and the columns are module-level and
reused across parses, with the side arrays released after each processor walk
so a parse never pins its source. Tree construction, node structure, offsets
and skip behavior are unchanged: the html5lib corpus (8389 tree-construction +
tokenizer inputs) serializes byte-identically to the previous object AST,
including all skip combinations and fragment modes.

Retained AST heap on a 2.4MB attribute-heavy document drops ~56% (45.2MB →
19.7MB), and ~50% (30.9MB → 15.4MB) under HtmlParser's skip config, with
parse time neutral to slightly faster.
One attribute is now an integer id into parallel columns (name/value offsets
plus one flags byte); an element holds a contiguous run (start + count). The
value string is derived from the source by offset on read — only valueless
attributes and offset-less adoption-agency clones store an override — and the
html5lib serializer name is derived from the adjusted name plus a namespace
flag, so per attribute only the interned name pointer is retained. Repeated
`<html>`/`<body>` tags merge by re-allocating the element's run; foreign-
content adjusts rewrite the run in place. `A` gains scalar attr accessors
(attrCount/attrAt/findAttr/attrName/attrValue/attr*Start/attr*End) used by
`HtmlParser`; `A.attributes` stays as a materializing test convenience.

Byte-identical: the 8389-input html5lib differential corpus (trees, offsets,
attribute spans, all skip combos, fragment modes) matches the object AST
exactly.

Cumulative retained AST heap on the 2.4MB benchmark document vs the object
AST, now counting typed-array backing stores (the previous commit's figures
missed them — heapUsed excludes ArrayBuffers): 45.2MB → 19.4MB (−57%) full,
30.9MB → 9.9MB (−68%) under HtmlParser's skip config; median parse time
~15% faster in both configs.
Visitors now receive the language's AST accessor as their first argument —
`(api, node, parent, ctx)` — for both the CSS and HTML `SourceProcessor`s,
so a consumer needs nothing beyond what the walk hands it (no module-level
`A` import), and the accessor can later become per-parse state without
touching any visitor. The generic visitor typedefs gain a `TApi` parameter;
each grammar passes its own accessor (`CssAst` / `HtmlAst` typedefs).

Rename the abbreviated HTML accessor methods to full names —
`attributeCount` / `attributeAt` / `findAttribute` / `attributeName` /
`attributeValue` / `attributeNameStart`-`attributeValueEnd` — plus the
`HtmlAttributeRef` / `AttributeRun` typedefs and the tokenizer's local
attribute state (the CSS accessor already used full words). No behavior
change: the html5lib differential corpus (8389 inputs) still serializes
byte-identically, and parse time is unchanged in both parsers.
Drop `HtmlParser`'s import of the accessor object entirely: the element and
comment visitors read through the `api` they receive, and the two helpers
that inspect attributes outside a visitor body (`attrSourceSpan`,
`reconcileScriptTypeAttr`) take the accessor as a parameter. `HtmlParser`
now consumes the parser exactly as an external package user would — nothing
but `SourceProcessor`, `NodeType`, and what the walk hands each visitor.

The accessor export stays: consumers that call `buildHtmlAst` directly
(without a walk) — the html5lib serializer and unit-test materializer — can
only read refs through it.
Visitors now receive a single `path` argument (Babel's `path` shape): the
language's accessor object with the walk's current position on it —
`path.node`, `path.parent` (null at a root) and `path.skipChildren()` —
and every field-read method defaulting to the current node
(`path.tagName()`, `path.findAttribute("type")`, explicit refs still
accepted: `path.tagName(other)`). The path is one reused module-level object
whose position is rebound before each callback, so unlike Babel there is no
per-node path allocation; it is only valid during the callback, and future
per-node functionality lands on it without touching visitor signatures.
The current position lives in module variables exposed through getters
(avoids self-referential `this` typing in the object literal), and the
per-process() visitor-context closure is gone.

The HTML walk is now iterative over the SoA link columns (firstChild /
nextSibling descend, the parent column ascends; template content fragments
gained a parent link for the ascent), with no recursion at all. This removes
the recursion depth limit: ~100k-deep nesting previously threw
`RangeError: Maximum call stack size exceeded` in the walk, and now
completes. The tree-link accessor `parent(n)` was renamed `parentOf(n)`
to free `path.parent` for the position field.

Measured on interleaved A/B runs against the previous commit: parse+walk
time and retained memory are unchanged in both parsers (deltas < 1.5%,
within noise); the html5lib differential corpus (8389 inputs) still
serializes byte-identically.
Copilot AI review requested due to automatic review settings July 3, 2026 12:37
@changeset-bot

changeset-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2e4fa23

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 Jul 3, 2026

Copy link
Copy Markdown
Contributor

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

Install it locally:

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

@codecov

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.50173% with 39 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.63%. Comparing base (5ce1c22) to head (2e4fa23).

Files with missing lines Patch % Lines
lib/html/syntax.js 94.88% 35 Missing ⚠️
lib/html/HtmlParser.js 96.42% 3 Missing ⚠️
lib/css/syntax.js 98.63% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #21331      +/-   ##
==========================================
+ Coverage   92.50%   92.63%   +0.13%     
==========================================
  Files         594      594              
  Lines       65387    65758     +371     
  Branches    18228    18269      +41     
==========================================
+ Hits        60483    60917     +434     
+ Misses       4904     4841      -63     
Flag Coverage Δ
css-parsing 28.64% <70.70%> (+0.04%) ⬆️
html5lib 28.38% <41.75%> (+0.19%) ⬆️
integration 88.79% <68.74%> (-0.09%) ⬇️
test262 45.47% <3.03%> (-0.07%) ⬇️
unit 43.67% <89.38%> (+0.52%) ⬆️

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.

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 webpack’s experimental HTML (and related CSS) parsing pipeline by switching the HTML AST to a struct-of-arrays (SoA) representation and migrating both HTML/CSS visitors to a single, reusable Babel-style path argument, reducing allocations and enabling an iterative walk to avoid deep-recursion stack overflows.

Changes:

  • Replaced the HTML AST’s object-per-node layout with an SoA backend accessed via a new exported accessor A.
  • Updated HTML and CSS visitor APIs to receive a single path accessor object (including skipChildren()), aligning both grammars.
  • Updated/added tests and a changeset to validate SoA access and visitor behavior (including html5lib serialization).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
test/walkCssTokensParser.unittest.js Updates tests to use the new CSS path visitor argument instead of node helpers.
test/html5lib.spectest.js Serializes the HTML tree via accessor A and SoA sibling/child links for corpus verification.
test/buildHtmlAst.unittest.js Materializes the SoA tree into plain objects for assertions; exercises the full accessor surface.
lib/util/SourceProcessor.js Updates the generic visitor types/docs to the new single-argument path visitor shape.
lib/html/syntax.js Implements the SoA HTML AST, accessor A, and an iterative tree walk behind SourceProcessor.
lib/html/HtmlParser.js Migrates HTML processing to the path/accessor-based visitor API and attribute ref reads.
lib/css/syntax.js Migrates the CSS walker to the single path visitor API and adds node/parent bindings.
lib/css/CssParser.js Updates CSS parser visitors to consume the new path argument and skipChildren() behavior.
.changeset/html-parser-soa-ast.md Adds a patch changeset describing the memory reduction improvement.
Comments suppressed due to low confidence (1)

lib/html/HtmlParser.js:1353

  • attrSourceSpan assumes the attribute has valid source offsets (attributeNameStart(...) >= 0). For cloned/synthesized attributes (offsets -1), this would slice from a negative index and produce incorrect copied attribute text. Guard against offset-less attributes before copying them into copyableAttrsText.
												for (const copyableName of COPYABLE_SIBLING_ATTRS) {
													const copyableAttr = path.findAttribute(copyableName);
													if (copyableAttr !== 0) {
														copyableAttrsText += attrSourceSpan(
															path,
															source,
															copyableAttr
														);
														if (copyableName === "crossorigin") {

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

Comment thread test/buildHtmlAst.unittest.js Outdated
Comment on lines +83 to +90
default:
// Text / Comment
return {
type: /** @type {typeof NodeType.Text} */ (type),
data: A.data(ref),
start: A.start(ref),
end: A.end(ref)
};
Comment thread lib/util/SourceProcessor.js Outdated
Comment on lines +11 to +14
* A visitor receives a single `path` argument (the Babel `path` shape): the
* language's AST accessor with the current position on it — `path.node`,
* `path.parent` (0 = none) — plus `path.skipChildren()` (enter only) to stop
* the walk descending, and every field-read method (which defaults to the
Comment thread lib/html/syntax.js Outdated
Comment on lines +8306 to +8308
doctypePublicId() {
return _hDocPub;
},
Comment thread lib/html/syntax.js Outdated
Comment on lines +8312 to +8314
doctypeSystemId() {
return _hDocSys;
},
@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 3, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

…eview

The merge with main brought #21329's `<base href>` support, written against
the old node-object visitor API; adapt it to the path accessor
(`path.namespace()` / `path.findAttribute("href")` /
`path.attributeValue(ref)`).

Also address Copilot review comments: repair the unittest's `HtmlNodeRef`
typedef (a rename artifact referenced an undefined `MatNodeRef`), widen the
materializer's Text/Comment type cast to the union it actually handles, let
`doctypePublicId`/`doctypeSystemId` accept an optional node for call-shape
uniformity, and correct the `path.parent` doc (null at a root, not 0).
@codspeed-hq

codspeed-hq Bot commented Jul 3, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 84.51%

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

⚡ 5 improved benchmarks
✅ 139 untouched benchmarks

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory benchmark "lodash", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 850.9 KB 130.9 KB ×6.5
Memory benchmark "future-defaults", scenario '{"name":"mode-production","mode":"production"}' 11 MB 7.5 MB +45.62%
Memory benchmark "wasm-modules-sync", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 190.2 KB 131.7 KB +44.44%
Memory benchmark "asset-modules-source", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 245.9 KB 192 KB +28.06%
Memory benchmark "wasm-modules-sync", scenario '{"name":"mode-production","mode":"production"}' 7.9 MB 6.5 MB +22.15%

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 perf/html-parser-soa-ast (2e4fa23) with main (5ce1c22)

Open in CodSpeed

@alexander-akait alexander-akait force-pushed the perf/html-parser-soa-ast branch from 40342bc to e603447 Compare July 3, 2026 12:46
…ion edge cases

Fix the TS2345 in the foster-parenting test (cast inside the map callback
instead of annotating the parameter against the widened element type).

Add unit coverage for the new path accessor surface (HTML and CSS) and for
tree-construction paths previously only reached by the html5lib corpus:
column growth, skipped-comment text merging, template foster parenting,
colgroup recovery, select/hr/selectedcontent handling, Noah's Ark, adoption
agency attribute cloning, foreign-content integration points and attribute
adjustment, repeated-body attribute merging, frameset replacement, and
fragment-context parsing.
Copilot AI review requested due to automatic review settings July 3, 2026 13:13

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 9 out of 9 changed files in this pull request and generated 1 comment.

@@ -341,12 +340,10 @@ describe("walkCssTokens — SourceProcessor", () => {
new SourceProcessor()
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging perf/html-parser-soa-ast into main will be
99.36%
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/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.12%100%100%99.12%207, 227
   CodeGenerationResults.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.43%100%100%98.43%1641, 1960, 1967, 1975, 1997, 2000, 2939, 3418–3419, 3451, 4117, 4147, 4200–4201, 4205, 4210, 4226–4227, 4241–4242, 4247–4248, 4725, 4751, 526, 531, 5559, 5591, 5608, 5624, 5640, 5655, 5680–5681, 5683, 6011, 6016, 6022, 6025, 6037, 6039, 6043, 6059, 6074, 6106, 6160, 6184, 6298, 777–778
   Compiler.js99.56%100%100%99.56%1147–1148, 1156
   ConcatenationScope.js98.65%100%100%98.65%195
   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.js98.99%100%100%98.99%172–173, 189, 208, 282
   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.55%100%100%98.55%1100, 1103, 502–506, 508, 654
   ExternalModuleFactoryPlugin.js100%100%100%100%
   ExternalsPlugin.js100%100%100%100%
   FileSystemInfo.js99.52%100%100%99.52%182, 2382–2383, 2386, 2397, 2408, 2419, 280, 3823, 3838, 3862
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.42%100%100%98.42%413, 422, 424, 428
   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%661
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.89%100%100%97.89%1223, 1226, 1243, 1260, 1507, 1541, 1557, 1644, 2000, 2299, 2304–2314, 415, 419, 573
   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%527–528, 533, 535, 599
   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, 889
   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.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.33%100%100%97.33%282, 306, 309, 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/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.40%100%100%96.40%1251, 1351, 1355, 1417, 628, 647, 657–659, 661, 677–678, 683, 686, 688, 693, 698, 723, 729, 763, 769, 775, 780, 791, 800, 805–806, 808, 825, 831–832, 834
   ResolverCachePlugin.js100%100%100%100%
   getLazyHashedEtag.js100%100%100%100%
   mergeEtags.js100%100%100%100%
lib/config
   browserslistTargetHandler.js100%100%100%100%
   defaults.js99.33%100%100%99.33%1468–1470, 1478, 274,

@alexander-akait alexander-akait merged commit e6fb547 into main Jul 3, 2026
63 checks passed
@alexander-akait alexander-akait deleted the perf/html-parser-soa-ast branch July 3, 2026 17:06
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