Skip to content

perf: monomorphic ResolveRequest clones via cloneRequest helper#530

Closed
alexander-akait wants to merge 3 commits into
mainfrom
claude/review-pr-445-optimization-GudJH
Closed

perf: monomorphic ResolveRequest clones via cloneRequest helper#530
alexander-akait wants to merge 3 commits into
mainfrom
claude/review-pr-445-optimization-GudJH

Conversation

@alexander-akait
Copy link
Copy Markdown
Member

Rewrites the { ...request, ... } spread pattern used across every
request-producing plugin into a shared cloneRequest helper that writes
the canonical ResolveRequest fields as a fixed-order object literal.
V8 can then cache a single hidden class for the result, matching the
perf win from #445 (ParsePlugin, JoinRequestPlugin, JoinRequestPartPlugin)
without dropping unknown own properties — after the literal, any extra
string or symbol keys on the original request are copied over, so
plugin authors (e.g. webpack's ResolverCachePlugin) that attach custom
state to the request keep working unchanged.

Rewrites the `{ ...request, ... }` spread pattern used across every
request-producing plugin into a shared `cloneRequest` helper that writes
the canonical ResolveRequest fields as a fixed-order object literal.
V8 can then cache a single hidden class for the result, matching the
perf win from #445 (ParsePlugin, JoinRequestPlugin, JoinRequestPartPlugin)
without dropping unknown own properties — after the literal, any extra
string or symbol keys on the original request are copied over, so
plugin authors (e.g. webpack's ResolverCachePlugin) that attach custom
state to the request keep working unchanged.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 16, 2026

⚠️ No Changeset found

Latest commit: 19e6f57

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

@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla Bot commented Apr 16, 2026

CLA Not Signed

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 16, 2026

Codecov Report

❌ Patch coverage is 93.75000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 96.72%. Comparing base (b5259a0) to head (19e6f57).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
lib/Resolver.js 93.75% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #530      +/-   ##
==========================================
- Coverage   96.75%   96.72%   -0.04%     
==========================================
  Files          50       50              
  Lines        2589     2592       +3     
  Branches      788      790       +2     
==========================================
+ Hits         2505     2507       +2     
- Misses         69       70       +1     
  Partials       15       15              
Flag Coverage Δ
integration 96.72% <93.75%> (-0.04%) ⬇️

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.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 16, 2026

Merging this PR will improve performance by 66.75%

⚡ 1 improved benchmark
✅ 42 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
pathological-deep-stack: alias chain of 50 (warm) 40.6 ms 24.4 ms +66.75%

Comparing claude/review-pr-445-optimization-GudJH (19e6f57) with main (b5259a0)

Open in CodSpeed

claude added 2 commits April 16, 2026 21:49
…oResolve

`doResolve` ran on every plugin step (~10-15 per resolve), and both of
the per-call costs stacked up under the CodSpeed `--no-opt` flags:

- The recursion-detection Set was cloned on every step via
  `new Set(resolveContext.stack)`, giving O(depth^2) Set work per
  top-level resolve. Switched to one Set per top-level resolve with
  add-on-entry / delete-on-exit around the hook call. Recursion
  semantics are preserved because the Set mirrors the live path.
- When `resolveContext.log` is not set (the production hot path), the
  previous code still allocated a fresh options literal and ran
  `createInnerContext` (which returned yet another literal). With the
  stack now shared by reference, the inner context is structurally
  identical to the parent; forward it directly and only fall through to
  `createInnerContext` when log wrapping is actually needed.

Benchmark (wall-clock under the package's `--no-opt --predictable`
flags, branch vs main):

  pathological-deep-stack:  +31.2%   (13.3 -> 9.16 ms)
  alias-realistic:          +28.6%
  array-alias:              +24.0%
  multiple-modules:         +9.9%
  symlinks (off):           +10.1%
  alias-field:              +8.4%
  realistic-midsize (warm): +7.2%
  main-field:               +6.1%
  description-files-multi:  +6.0%
  mixed-conditions:         +5.4%
  query-fragment:           +4.9%
  concurrent-batch:         +3.4%

The pathological-deep-stack case is the direct validation of the Set
change: with a 50-deep alias chain, removing the O(N^2) snapshotting
matches the theoretical win exactly.
@alexander-akait alexander-akait deleted the claude/review-pr-445-optimization-GudJH branch April 17, 2026 14:13
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