Skip to content

fix: make TsconfigPathsPlugin work with sync file systems (#571)#572

Merged
alexander-akait merged 4 commits into
mainfrom
claude/fix-issue-571-uMgNu
May 7, 2026
Merged

fix: make TsconfigPathsPlugin work with sync file systems (#571)#572
alexander-akait merged 4 commits into
mainfrom
claude/fix-issue-571-uMgNu

Conversation

@alexander-akait

Copy link
Copy Markdown
Member

The plugin used async/await and Promise-wrapped file system calls, so its
tapAsync handlers always deferred callback invocation by a Promise tick.
That caused resolveSync to throw "fileSystem is not sync" whenever
tsconfig was enabled, even with useSyncFileSystemCalls: true. Convert the
plugin and util/fs#readJson to callback-based code so a synchronous file
system stays synchronous all the way through, and resolveSync works as
expected.

claude added 2 commits May 7, 2026 17:49
The plugin used async/await and Promise-wrapped file system calls, so its
tapAsync handlers always deferred callback invocation by a Promise tick.
That caused resolveSync to throw "fileSystem is not sync" whenever
tsconfig was enabled, even with useSyncFileSystemCalls: true. Convert the
plugin and util/fs#readJson to callback-based code so a synchronous file
system stays synchronous all the way through, and resolveSync works as
expected.
- Dedupe the two `apply()` tapAsync handlers into a small `tap` helper
  parameterised by hook name, target hook, field picker, and resolve
  handler.
- Drop the dead `done` guard in `_loadTsconfigReferences` — `pending`
  cannot legitimately reach 0 twice.
- Collapse the array-vs-scalar `extends` branches in `_loadTsconfig`
  into a single trampoline by normalising scalar to a 1-element list.
- Drop the unused `cb` alias and the cast it required by marking
  `_loadTsconfig`'s callback non-optional.
- Trim issue-referencing test names and a duplicate comment block.
@changeset-bot

changeset-bot Bot commented May 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d106a4e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
enhanced-resolve 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 May 7, 2026

Copy link
Copy Markdown

CLA Not Signed

@codspeed-hq

codspeed-hq Bot commented May 7, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 24.26%

⚡ 3 improved benchmarks
❌ 1 regressed benchmark
✅ 134 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory node-compare: enhanced-resolve async x 1000 (fs cache) 1,185.8 KB 788.8 KB +50.33%
Memory unsafe-cache: ON, 3x repeat 4.1 KB 1.7 KB ×2.5
Memory unsafe-cache-miss-heavy: 1 miss pass + 1 hit pass 4.1 KB 1.2 KB ×3.5
Memory node-compare: enhanced-resolve sync x 1000 (fs cache) 597.5 KB 788.9 KB -24.26%

Comparing claude/fix-issue-571-uMgNu (d106a4e) with main (e1f07eb)

Open in CodSpeed

@codecov

codecov Bot commented May 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.20280% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.54%. Comparing base (e1f07eb) to head (d106a4e).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
lib/TsconfigPathsPlugin.js 96.66% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #572      +/-   ##
==========================================
+ Coverage   96.51%   96.54%   +0.03%     
==========================================
  Files          50       50              
  Lines        2895     2927      +32     
  Branches      911      922      +11     
==========================================
+ Hits         2794     2826      +32     
  Misses         85       85              
  Partials       16       16              
Flag Coverage Δ
integration 96.54% <97.20%> (+0.03%) ⬆️

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.

claude added 2 commits May 7, 2026 18:26
The previous simplification factored apply() through a `tap` closure that
allocated a `pickField` arrow per hook and called it on every resolve, and
extracted `_addFileDependencies` as a method. Both add small per-resolve
overhead that shows up in CodSpeed instruction counts. Inline the two
tapAsync handlers and the file-dependency loop back into the hot path.
Also shorten the changeset to a one-liner.
Three small allocations were happening on every cold-path tsconfig load
that had no equivalent in main:
  - the {stripComments: true} options literal passed to readJson — hoist
    to a module-level READ_JSON_OPTIONS constant.
  - the [extendedConfig] wrapper array on the scalar `extends` branch —
    restore a separate scalar code path so the string is passed through
    directly.
  - the `finish` closure that built the TsconfigPathsMap — extract to a
    module-level `buildTsconfigPathsMap` helper called from both the
    references and no-references branches.

tsconfig-extends and tsconfig-paths benches each pick up roughly +30%
ops/s locally.
@alexander-akait alexander-akait merged commit 2f41af2 into main May 7, 2026
33 of 35 checks passed
@alexander-akait alexander-akait deleted the claude/fix-issue-571-uMgNu branch May 7, 2026 19:22
alexander-akait pushed a commit that referenced this pull request May 7, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## enhanced-resolve@5.21.1

### Patch Changes

- Allocation-free reductions on hot-path code: hoist `/#/g`, `/\$/g` and
`/\\/g` to module-level constants and gate the corresponding `.replace`
calls behind `includes(…)` so paths/queries/requests without the match
char skip the regex state machine entirely (the common case); share a
single `EMPTY_NO_MATCH` tuple instead of allocating `[[], null]` per "no
match" / "no condition matched" return; switch `directMapping`'s
`for...of` over `mappingTarget` and inner results to indexed loops to
avoid iterator-object allocation per call; inline `isConditionalMapping`
at its two hot-path call sites and merge the duplicate `default` /
`conditionNames.has(condition)` branches in `computeConditionalMapping`;
replace `invalidSegmentRegEx.exec(…) !== null` with `.test(…)` (no
match-array allocation); drop the dead
`deprecatedInvalidSegmentRegEx.test(…) !== null` clause in
`ImportsFieldPlugin` (`.test` returns boolean; `true !== null` and
`false !== null` are both true, so it was `&& true`); drop the redundant
`relativePath.length === 0` guard before `!startsWith("./")` in
`ExportsFieldPlugin` (the empty-string case is already covered). (by
[@alexander-akait](https://github.com/alexander-akait) in
[#558](#558))

- restore plugin compatibility for `[...resolveContext.stack]` iteration
(by [@alexander-akait](https://github.com/alexander-akait) in
[#569](#569))

- fix `TsconfigPathsPlugin` to support `resolveSync` with
`useSyncFileSystemCalls` (by
[@alexander-akait](https://github.com/alexander-akait) in
[#572](#572))

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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