Visitar URL original
fix(tsconfig): optimize TsconfigPathsPlugin and fix extends resolution bugs by xiaoxiaojx · Pull Request #483 · webpack/enhanced-resolve · GitHub
Skip to content

fix(tsconfig): optimize TsconfigPathsPlugin and fix extends resolution bugs - #483

Merged
alexander-akait merged 2 commits into
mainfrom
fix/tsconfig-paths-optimizations
Mar 16, 2026
Merged

alexander-akait merged 2 commits into
mainfrom
fix/tsconfig-paths-optimizations

Conversation

@xiaoxiaojx

@xiaoxiaojx xiaoxiaojx commented Mar 15, 2026 •

Copy link
Copy Markdown
Member

Summary
Perf/cleanup:

  • Remove redundant slice in getPrefixLength (return indexOf result directly)
  • Precompute allContexts in _loadTsconfigPathsMap to avoid per-call object rebuild
  • Parallelize _loadTsconfigReferences with Promise.all instead of sequential await

Bug fixes:

  • Fix baseUrl inheritance from deep extends chains: use dirname(extendedConfigPath) (absolute) instead of dirname(extendedConfigValue) (relative), so non-sibling directory structures resolve correctly
  • Fix scoped npm package extends (@scope/name): add fallback to resolve node_modules/@scope/name/tsconfig.json when node_modules/@scope/name.json is not found TSConfig extends does not resolve Node.js style specifiers microsoft/TypeScript#62753

Add test fixtures and cases covering both bug scenarios.

What kind of change does this PR introduce?
fix

Did you add tests for your changes?

Yes

Does this PR introduce a breaking change?

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

Use of AI
Partial

xiaoxiaojx and others added 2 commits March 15, 2026 20:23
…n bugs

Perf/cleanup:
- Remove redundant slice in getPrefixLength (return indexOf result directly)
- Precompute allContexts in _loadTsconfigPathsMap to avoid per-call object rebuild
- Parallelize _loadTsconfigReferences with Promise.all instead of sequential await

Bug fixes:
- Fix baseUrl inheritance from deep extends chains: use dirname(extendedConfigPath)
  (absolute) instead of dirname(extendedConfigValue) (relative), so non-sibling
  directory structures resolve correctly
- Fix scoped npm package extends (@scope/name): add fallback to resolve
  node_modules/@scope/name/tsconfig.json when node_modules/@scope/name.json
  is not found

Add test fixtures and cases covering both bug scenarios.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov

codecov Bot commented Mar 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.42%. Comparing base (8148159) to head (cbcc384).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #483      +/-   ##
==========================================
+ Coverage   93.40%   93.42%   +0.02%     
==========================================
  Files          50       50              
  Lines        2502     2511       +9     
  Branches      759      766       +7     
==========================================
+ Hits         2337     2346       +9     
  Misses        136      136              
  Partials       29       29              
Flag Coverage Δ
integration 93.42% <100.00%> (+0.02%) ⬆️

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.

@alexander-akait
alexander-akait merged commit 6d27b83 into main Mar 16, 2026
28 checks passed
@alexander-akait
alexander-akait deleted the fix/tsconfig-paths-optimizations branch March 16, 2026 15:27
alexander-akait pushed a commit that referenced this pull request Nov 12, 2026
<!-- Thanks for submitting a pull request! Please provide enough
information so that others can review your pull request. -->

**Summary**

<!-- Explain the **motivation** for making this change. What existing
problem does the pull request solve? -->
<!-- Try to link to an open issue for more information. -->
<!-- Any other information related to changes. -->

Fixes #706.

`TsconfigPathsPlugin` builds `extends` paths by hand. It appends `.json`
to any value without `.json` in it, and maps package names to
`node_modules` paths itself. tsc treats `./`, `../` and absolute values
as files (`.json` optional) and resolves everything else like a
`require`. So four forms that tsc accepts fail the whole tsconfig,
including the project's own `paths`.

This keeps the file branch and resolves everything else with a child
resolver set up like tsc's config lookup: `exports` with the
`require`/`types`/`node` conditions, the `tsconfig` field, then
`tsconfig.json`. That replaces the package special cases added in #483,
#575 and #631. Like tsc, backslashes are normalized first. When the
lookup fails, a bare file name such as `"tsconfig.base.json"` still
loads from the config's directory, as it always has here, though tsc
rejects it.

Resolving `@/foo` with the #706 repro, where tsc gives `src/foo.ts` for
all four:

| `extends` | Before | After |
| ---------------------------------- |
------------------------------------------ | ------------ |
| `"cfgpkg/strict"` via `exports` | `ENOENT …
node_modules/cfgpkg/strict.json` | `src/foo.ts` |
| `"cfgpkg"` with a `tsconfig` field | `ENOENT …
node_modules/cfgpkg/tsconfig.json` | `src/foo.ts` |
| `"./configs/base.tsconfig"` | `ENOENT … configs/base.tsconfig.json` |
`src/foo.ts` |
| `".."` | `ENOENT … dotdot/pkg/...json` | `src/foo.ts` |

<!-- In addition to that please answer these questions: -->

**What kind of change does this PR introduce?**

<!-- E.g. a fix, feat, refactor, perf, test, chore, ci, build, style,
revert, docs or describe it if you did not find a suitable kind of
change. -->

fix

**Did you add tests for your changes?**

<!-- Please note: in most cases, if you change the code, we will not
merge your changes unless you add tests. -->

Yes: five cases in `test/tsconfig-paths.test.js`, with fixtures in
`test/fixtures/tsconfig-paths/extends-resolution/`. The four #706 forms
fail on `main`. The `..` case also checks that a sibling `<dir>.json`
doesn't win. The bare file name case passes on `main` and guards the
kept fallback.

**Does this PR introduce a breaking change?**

<!-- If this PR introduces a breaking change, please describe the impact
and a migration path for existing applications. -->

No.

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

<!-- List all the information that needs to be added to the
documentation after merge that has already been documented in this PR.
-->

n/a

**Use of AI**

<!-- If you have used AI, please state so here. Explain how you used it.
Make sure to read our AI policy
(https://github.com/webpack/governance/blob/main/AI_POLICY.md) or your
Pull Request may be closed due to irresponsible use of AI. -->

Yes. I used Claude Code to write the change and the tests. I reviewed
every line, checked each case against tsc's `getExtendsConfigPath`, and
ran `npm run lint` and the full test suite locally.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

<!-- coderabbit-ai-generated:v1 -->

## Summary by CodeRabbit

* **Bug Fixes**
* TypeScript configuration inheritance now follows TypeScript-style path
resolution, including package exports, package configuration fields,
extensionless config files, and parent-directory references.
* Unsupported bare filenames are no longer treated as valid
configuration paths.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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