Skip to content

perf: cache conditionalMapping + per-plugin description-file lookups#556

Merged
alexander-akait merged 2 commits intomainfrom
claude/perf-improvements-caching-vftdy
Apr 23, 2026
Merged

perf: cache conditionalMapping + per-plugin description-file lookups#556
alexander-akait merged 2 commits intomainfrom
claude/perf-improvements-caching-vftdy

Conversation

@alexander-akait
Copy link
Copy Markdown
Member

On every resolve that descends through a description file, plugins were
re-walking the same package.json content to answer questions whose
inputs are stable: does this file have an exports/imports/alias field,
what's the main module, does a conditional mapping resolve to the same
target under the resolver's fixed condition set. Add narrow caches that
key on stable object references (parsed JSON content, conditional
mapping objects, conditionNames Sets) so repeat resolves against the
same package skip the lookup work.

  • util/entrypoints.js: memoize conditionalMapping(mapping, conditionNames)
    in a WeakMap<ConditionalMapping, WeakMap<Set<string>, ...>>. Uses a
    sentinel for null results so the hit path is a single get().
  • ExportsFieldPlugin/ImportsFieldPlugin: cache null in the existing
    per-content processor WeakMap for description files that have no
    exports/imports field, skipping the DescriptionFileUtils.getField
    walk on subsequent resolves. Builds the processor inside the existing
    try/catch so malformed fields still surface their error.
  • MainFieldPlugin: cache the fully-resolved mainModule string (with
    forceRelative already applied) per content, with a NO_MAIN sentinel
    for packages whose main field is absent / "." / "./".
  • AliasFieldPlugin: cache the resolved alias-map object per content
    (or a sentinel when the field isn't a valid alias config).
  • SelfReferencePlugin: cache the "name" string per content when
    self-reference applies (or a sentinel when it can't).

Benchmarks (--no-opt, local):

realistic-midsize warm: 723 ops/s -> 763 ops/s (+5.5%)
realistic-midsize cold: 34.0 -> 34.7 (+2%)
exports-patterns-many: 507 -> 526 (+3.8%)
mixed-conditions: 2718 -> 2730-2765 (
+1%)
self-reference: 2233 -> 2265 (+1.4%)
exports-field (warm): ~1240 -> ~1230 (within noise)

https://claude.ai/code/session_01JM6aPUSLLfmEdtxeffMAiZ

On every resolve that descends through a description file, plugins were
re-walking the same `package.json` content to answer questions whose
inputs are stable: does this file have an exports/imports/alias field,
what's the main module, does a conditional mapping resolve to the same
target under the resolver's fixed condition set. Add narrow caches that
key on stable object references (parsed JSON content, conditional
mapping objects, conditionNames Sets) so repeat resolves against the
same package skip the lookup work.

* `util/entrypoints.js`: memoize `conditionalMapping(mapping, conditionNames)`
  in a `WeakMap<ConditionalMapping, WeakMap<Set<string>, ...>>`. Uses a
  sentinel for `null` results so the hit path is a single `get()`.
* `ExportsFieldPlugin`/`ImportsFieldPlugin`: cache `null` in the existing
  per-content processor WeakMap for description files that have no
  exports/imports field, skipping the `DescriptionFileUtils.getField`
  walk on subsequent resolves. Builds the processor inside the existing
  try/catch so malformed fields still surface their error.
* `MainFieldPlugin`: cache the fully-resolved `mainModule` string (with
  forceRelative already applied) per content, with a `NO_MAIN` sentinel
  for packages whose main field is absent / "." / "./".
* `AliasFieldPlugin`: cache the resolved alias-map object per content
  (or a sentinel when the field isn't a valid alias config).
* `SelfReferencePlugin`: cache the `"name"` string per content when
  self-reference applies (or a sentinel when it can't).

Benchmarks (--no-opt, local):

  realistic-midsize warm:   723 ops/s -> ~763 ops/s  (+5.5%)
  realistic-midsize cold:   34.0      -> ~34.7       (~+2%)
  exports-patterns-many:    507       -> 526         (+3.8%)
  mixed-conditions:        2718       -> 2730-2765   (~+1%)
  self-reference:          2233       -> 2265        (+1.4%)
  exports-field (warm):    ~1240      -> ~1230       (within noise)

https://claude.ai/code/session_01JM6aPUSLLfmEdtxeffMAiZ
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 23, 2026

⚠️ No Changeset found

Latest commit: c8ca041

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 changesets to release 1 package
Name Type
enhanced-resolve Patch

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 23, 2026

CLA Not Signed

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 23, 2026

Codecov Report

❌ Patch coverage is 95.74468% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.53%. Comparing base (26f15b0) to head (c8ca041).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/SelfReferencePlugin.js 88.88% 2 Missing ⚠️
lib/ImportsFieldPlugin.js 93.33% 1 Missing ⚠️
lib/util/entrypoints.js 94.11% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #556      +/-   ##
==========================================
- Coverage   96.64%   96.53%   -0.11%     
==========================================
  Files          50       50              
  Lines        2830     2887      +57     
  Branches      881      901      +20     
==========================================
+ Hits         2735     2787      +52     
- Misses         79       84       +5     
  Partials       16       16              
Flag Coverage Δ
integration 96.53% <95.74%> (-0.11%) ⬇️

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 23, 2026

Merging this PR will improve performance by 29.86%

⚡ 1 improved benchmark
✅ 68 untouched benchmarks

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation exports-field: conditions=import,node (warm) 2.4 ms 1.9 ms +29.86%

Comparing claude/perf-improvements-caching-vftdy (c8ca041) with main (26f15b0)

Open in CodSpeed

@alexander-akait alexander-akait merged commit fd688b1 into main Apr 23, 2026
30 of 33 checks passed
@alexander-akait alexander-akait deleted the claude/perf-improvements-caching-vftdy branch April 23, 2026 14:50
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