Skip to content

Regression (11.21.3): solution-style root tsconfig (files: [] + references) no longer applies its paths to files no referenced project owns #1345

Description

@valentinpalkovic

Summary

Since v11.21.3, tsconfig: 'auto' no longer applies a solution-style root tsconfig's compilerOptions.paths to files that no referenced project owns.
In v11.21.2 such files fell back to the nearest tsconfig's paths; from v11.21.3 they get no tsconfig at all, so every path alias stops resolving for them.

The only tsconfig change in v11.21.3 is #1220 ("only attach an auto-discovered tsconfig to a file it owns"), so I am fairly confident that is where the behavior flipped.
It looks like the sibling case of #1159: that one was about a root with references and an omitted include, this one is about an explicit files: [] root whose references simply do not cover the importing file.

Reproduction

repro/
├── tsconfig.json          { compilerOptions: { moduleResolution: "bundler",
│                            paths: { "@app/*": ["./src/libs/*"] } },
│                            files: [], references: [{ "path": "./tsconfig.app.json" }] }
├── tsconfig.app.json      { extends: "./tsconfig.json", files: ["app/main.ts"] }
├── app/main.ts            export {};
├── src/libs/util.ts       export const util = 'util';
└── stories/story.ts       import { util } from '@app/util';   ← owned by NO referenced project
// repro.mjs — npm i oxc-resolver && node repro.mjs
import { ResolverFactory } from 'oxc-resolver';
import { fileURLToPath } from 'node:url';
const dir = fileURLToPath(new URL('.', import.meta.url));
const resolver = new ResolverFactory({ tsconfig: 'auto', extensions: ['.ts'] });
const result = resolver.resolveFileSync(dir + 'stories/story.ts', '@app/util');
console.log(process.env.OXC_LABEL, '->', result?.path ?? result?.error ?? result);

Captured output:

oxc-resolver@11.21.2 -> /…/repro/src/libs/util.ts
oxc-resolver@11.21.3 -> Cannot find module '@app/util'
oxc-resolver@11.24.2 -> Cannot find module '@app/util'

Why this bites in the wild

Every Angular CLI workspace since v15 generates exactly this shape by default: a solution-style root tsconfig.json with files: [] and references to tsconfig.app.json / tsconfig.spec.json, with paths living on the root.
Anything that is not part of the app or spec projects - Storybook story files are the case we hit, in .storybook/ or a stories/ directory - is owned by no referenced project, and from v11.21.3 loses all path aliases.

We found this while evaluating Storybook's Angular docgen (which resolves story imports through oxc-resolver with tsconfig: 'auto') against real-world repos; on BIRU-Scop/tenzu-front the components imported via @tenzu/* aliases silently stopped resolving.
Storybook pins oxc-resolver: ^11.19.1, so fresh installs float onto the broken 11.24.x while our own repo's lockfile holds 11.19.1 - which is why our CI never caught it.

Expected behavior

I can see the argument that a files: [] root owns nothing per the TypeScript spec, so strictly there is no config to attach.
But the pre-11.21.3 fallback matched what the tsconfig-paths ecosystem (and editors, practically speaking) do with orphan files in solution-style workspaces, and dropping it breaks the default output of ng new.
My suggestion would be: when the discovered tsconfig is solution-style and no referenced project claims the file, fall back to the solution config's own paths instead of attaching nothing.

Happy to provide more details or test a fix - the repro above is self-contained.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

Priority

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions