Skip to content

fix: Resolve TypeScript .js extension imports to .ts files in boundaries#12644

Merged
anthonyshew merged 1 commit into
vercel:mainfrom
maschwenk:fix/boundaries-tsconfig-js-to-ts-extension-alias
May 6, 2026
Merged

fix: Resolve TypeScript .js extension imports to .ts files in boundaries#12644
anthonyshew merged 1 commit into
vercel:mainfrom
maschwenk:fix/boundaries-tsconfig-js-to-ts-extension-alias

Conversation

@maschwenk

@maschwenk maschwenk commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Description

turbo boundaries still incorrectly flags tsconfig paths aliases in ESM TypeScript projects (moduleResolution: "nodenext" or "bundler"). Given:

// tsconfig.json
{ "compilerOptions": { "paths": { "test/*": ["./test/*"] } } }
import { Factory } from "test/factories/foo.js"; // real file: ./test/factories/foo.ts

turbo boundaries reports:

× cannot import package `test` because it is not a dependency

This is the same symptom as

In

fixed the specific case where the resolver can resolve the alias, but did not teach the resolver TypeScript's rule that an explicit .js in the import specifier should fall back to .ts/.tsx/.d.ts on disk. That's why the still-reproducible follow-up comment on #11906 ("this still isn't solved for me (2.8.17)") is a real bug and not user error.

Root cause

Tracer::create_resolver in crates/turbo-trace/src/tracer.rs registered .ts, .tsx, etc. as extensions to try when one is absent, but didn't set ResolveOptions::extension_alias. So after tsconfig alias substitution, the resolver looks for the literal .js file, gets NotFound, check_import_as_tsconfig_path_alias returns false, and the import falls through to check_package_import. For package-name-shaped aliases (test/*, features/*, etc.) that becomes an "undeclared dependency" diagnostic.

Scoped-looking aliases like @/foo silently pass today only because is_potential_package_name rejects @/<name> (the scope must be non-empty), skipping the package-check step. Same underlying bug, different visible behavior.

Fix

Configure extension_alias to mirror TypeScript's nodenext / bundler resolution (and webpack's resolve.extensionAlias):

  • .js.ts, .tsx, .d.ts, .js, .jsx
  • .mjs.mts, .mjs
  • .cjs.cts, .cjs

Real npm-package imports that resolve through node_modules still return false (thanks to the existing node_modules component check in check_import_as_tsconfig_path_alias) and fall through to the dependency-declaration check — so undeclared-dependency diagnostics are not weakened for real packages.

Testing Instructions

Two regression tests added in crates/turborepo-boundaries/src/imports.rs:

  • tsconfig_alias_resolves_js_extension_to_ts_file — reproduces the exact scenario from the bug report: a test/* tsconfig alias, a .js-extension import, and a .ts file on disk.
  • tsconfig_alias_resolves_mjs_extension_to_mts_file — covers the .mjs.mts rewrite path.
cargo test -p turborepo-boundaries tsconfig_alias_resolves_js_extension_to_ts_file
cargo test -p turborepo-boundaries tsconfig_alias_resolves_mjs_extension_to_mts_file
cargo test -p turborepo-boundaries # full boundaries test suite

Manual reproduction

A minimal reproduction is an ESM TypeScript app with:

// package.json
{ "type": "module" }

// tsconfig.json
{
  "compilerOptions": {
    "module": "nodenext",
    "moduleResolution": "nodenext",
    "paths": { "test/*": ["./test/*"] }
  }
}
// test/factories/foo.ts
export const foo = {};

// src/index.ts
import { foo } from "test/factories/foo.js"; // flagged before this fix, resolves after

Before this PR: turbo boundaries reports "cannot import package test because it is not a dependency".
After this PR: no diagnostic.

Fixes #11906.

Made with Cursor

@vercel

vercel Bot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

@maschwenk is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

@maschwenk maschwenk force-pushed the fix/boundaries-tsconfig-js-to-ts-extension-alias branch from 8487770 to 7f7df93 Compare April 21, 2026 21:37
@maschwenk maschwenk marked this pull request as ready for review April 22, 2026 15:44
@maschwenk maschwenk requested a review from a team as a code owner April 22, 2026 15:44
@maschwenk maschwenk requested review from tknickman and removed request for a team April 22, 2026 15:44

@anthonyshew anthonyshew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving but we do require signed commits. Are you able to get that set up and update the commits on this branch?

@maschwenk maschwenk force-pushed the fix/boundaries-tsconfig-js-to-ts-extension-alias branch from b2a62f3 to 4534ccf Compare May 5, 2026 21:45
@anthonyshew anthonyshew merged commit b47f6dc into vercel:main May 6, 2026
43 of 52 checks passed
anthonyshew pushed a commit that referenced this pull request May 7, 2026
## Release v2.9.10-canary.1

> [!CAUTION]
> Versioned docs aliasing FAILED. [View
logs](https://github.com/vercel/turborepo/actions/runs/25414005119)

### Changes

- fix: Preserve lockfiles during dry-run conversion (#12717) (`3192551`)
- ci: Fix LSP workflow container matrix (#12718) (`ac55ec9`)
- release(turborepo): 2.9.9-canary.4 (#12716) (`25c71b0`)
- release(turborepo): 2.9.9 (#12719) (`acfe475`)
- fix: Respect SCM env vars in `turbo query affected` (#12722)
(`3caa8fb`)
- ci: Package VSCode extension in release workflow (#12723) (`329a545`)
- fix: Avoid raw create-turbo example telemetry (#12725) (`ec0b8dd`)
- fix: Escape graph HTML payloads (#12726) (`89b4f4e`)
- fix: Prevent OTEL token injection to spoofed origins (#12727)
(`1fbc725`)
- fix: Retry HTTP status failures (#12728) (`e389d66`)
- fix: Validate microfrontend proxy Host header (#12730) (`eb46170`)
- fix: Redact task hash env debug logs (#12733) (`6d9fc06`)
- fix: Filter microfrontend proxy environments (#12732) (`9b28a75`)
- fix: Preserve FSEvents mount points for device-relative paths (#12729)
(`6ce73e0`)
- fix: Validate proxy Host headers (#12731) (`9f70395`)
- fix: Resolve TypeScript `.js` extension imports to `.ts` files in
boundaries (#12644) (`b47f6dc`)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
anthonyshew pushed a commit that referenced this pull request May 7, 2026
## Release v2.9.10

> [!CAUTION]
> Versioned docs aliasing FAILED. [View
logs](https://github.com/vercel/turborepo/actions/runs/25509373774)

### Changes

- release(turborepo): 2.9.9-canary.4 (#12716) (`25c71b0`)
- release(turborepo): 2.9.9 (#12719) (`acfe475`)
- fix: Respect SCM env vars in `turbo query affected` (#12722)
(`3caa8fb`)
- ci: Package VSCode extension in release workflow (#12723) (`329a545`)
- fix: Avoid raw create-turbo example telemetry (#12725) (`ec0b8dd`)
- fix: Escape graph HTML payloads (#12726) (`89b4f4e`)
- fix: Prevent OTEL token injection to spoofed origins (#12727)
(`1fbc725`)
- fix: Retry HTTP status failures (#12728) (`e389d66`)
- fix: Validate microfrontend proxy Host header (#12730) (`eb46170`)
- fix: Redact task hash env debug logs (#12733) (`6d9fc06`)
- fix: Filter microfrontend proxy environments (#12732) (`9b28a75`)
- fix: Preserve FSEvents mount points for device-relative paths (#12729)
(`6ce73e0`)
- fix: Validate proxy Host headers (#12731) (`9f70395`)
- fix: Resolve TypeScript `.js` extension imports to `.ts` files in
boundaries (#12644) (`b47f6dc`)
- fix: Use random temp path for repo downloads (#12736) (`106698c`)
- release(turborepo): 2.9.10-canary.1 (#12734) (`b1001c1`)
- fix: Reject OTel endpoints with userinfo (#12737) (`a6efc3f`)
- fix: Authenticate local devtools WebSocket (#12738) (`8276be8`)
- fix: Handle clipboard exec errors (#12739) (`3305766`)
- fix: Restrict Vercel token reuse to trusted API origins (#12740)
(`18a3a22`)
- fix: Keep workspace config discovery inside root (#12741) (`86c0365`)
- fix: Hardening for daemon IPC endpoints (#12742) (`13a9a8b`)
- fix: Enforce cache filesystem boundaries (#12743) (`a50e863`)

---------

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.

turbo boundaries does not understand tsconfig path aliases, incorrectly flags local imports as undeclared dependencies

2 participants