Skip to content

refactor(config): evaluate native Vite tsconfig paths#2546

Draft
james-elicx wants to merge 2 commits into
mainfrom
codex/native-tsconfig-paths-gap-repro
Draft

refactor(config): evaluate native Vite tsconfig paths#2546
james-elicx wants to merge 2 commits into
mainfrom
codex/native-tsconfig-paths-gap-repro

Conversation

@james-elicx

@james-elicx james-elicx commented Jul 6, 2026

Copy link
Copy Markdown
Member

Purpose

This is an intentionally red draft to evaluate replacing vinext's hand-written tsconfig paths materialization with Vite 8's native resolve.tsconfigPaths implementation.

It removes the custom machinery introduced by #655 and #2504:

  • root-only tsconfig/jsconfig parsing and extends handling
  • conversion of compilerOptions.paths into global resolve.alias entries
  • longest-prefix ordering for those synthetic aliases
  • stylesheet-importer detection
  • deprecated alias customResolver
  • suppression of Vite's customResolver deprecation warning
  • the duplicate tsconfig parser used while loading next.config.ts

Both application imports and next.config.ts imports now delegate to native Vite tsconfig resolution.

What works natively

The following targeted tests remain green:

vp test run tests/tsconfig-paths-vite8.test.ts tests/tsconfig-path-alias-resolution.test.ts tests/next-config.test.ts

3 files passed
221 tests passed

This covers:

Static validation is also green. The unrelated issue #659 MDX-frontmatter regression guard was restored using a relative glob and remains green:

vp check packages/vinext/src/index.ts packages/vinext/src/config/next-config.ts tests/tsconfig-paths-vite8.test.ts tests/tsconfig-path-alias-build.test.ts tests/helpers.ts

Intentional failing reproductions

tests/tsconfig-path-alias-build.test.ts contains three ordinary failing build tests. They are not skipped or marked as expected failures because the purpose of this draft is for CI to demonstrate the native Vite gaps clearly.

vp test run tests/tsconfig-path-alias-build.test.ts

3 build tests failed

1. import.meta.glob() in bundled environments

An alias-based glob such as:

import.meta.glob("@/content/posts/**/*.mdx", { eager: true })

is not expanded using resolve.tsconfigPaths in the bundled RSC build. The expected module never enters the bundle.

The JavaScript implementation of Vite's import-glob transform calls the plugin resolver, but bundled environments switch to the native Rolldown import-glob plugin, where the tsconfig path mapping is not applied to the glob prefix.

2. Variable dynamic imports

An alias-based variable import such as:

import(`@/content/posts/${slug}.mdx`)

survives into the emitted bundle with the raw alias prefix. The bundled dynamic-import-vars transform resolves/analyzes the pattern internally and does not apply native tsconfig path resolution to the static portion.

A user resolveId plugin is insufficient here: the bundled dynamic-import-vars path does not expose the unresolved template pattern through the normal plugin resolver before analysis.

3. Pre-existing nearest-importer tsconfig limitation

A nested lib/tsconfig.json can override @/* for modules under lib/. Native ordinary import resolution discovers that config per importer, but aliased glob expansion does not. The removed vinext materialization also failed this case because it only read the root tsconfig; this test documents a pre-existing correctness limitation rather than a regression caused by this draft.

This reproduction is important because a vinext fallback based on the root tsconfig would appear to remove the raw syntax while silently expanding against the wrong directory.

4. jsconfig.json while loading next.config.ts

The removed vinext parser searched both tsconfig.json and jsconfig.json. Vite native resolve.tsconfigPaths does not resolve next.config.ts imports from a project that has only jsconfig.json. This was initially hidden when the parser unit tests were deleted; the draft now includes an ordinary failing behavioral test in tests/next-config.test.ts.

This is a regression from the removed custom implementation and needs either native Vite jsconfig support or a narrow vinext compatibility path.

Recommendations

Preferred: fix this in Vite

The robust solution is for Vite's bundled transforms to use the same per-importer tsconfig resolver as ordinary module resolution:

  1. Teach the native import-glob transform to resolve the static glob prefix through resolve.tsconfigPaths, using the importing module to select the matching tsconfig.
  2. Teach the native dynamic-import-vars transform to resolve the static prefix of template imports through the same resolver before converting the expression to a glob.
  3. Alternatively, expose a public per-importer tsconfig-path resolution primitive that framework plugins can call with a pattern/static prefix rather than a concrete existing filename.
  4. Add Vite playground coverage for root and nested tsconfigs across ordinary imports, import.meta.glob, and variable dynamic imports.

This keeps tsconfig semantics in one implementation, retains Vite's native alias/build performance, and avoids framework-specific parsing.

Possible vinext fallback

If Vite cannot address this soon, vinext could add a narrowly filtered pre-transform for only:

  • import.meta.glob() string patterns
  • template-literal dynamic imports with a statically identifiable prefix

However, this is only viable if vinext uses a correct per-importer resolver. Reusing the removed root-only parser would be incorrect for nested tsconfigs, project references, multiple path targets, array extends, and future TypeScript/Vite semantics.

A vinext fallback should therefore either:

  • consume a public Vite/oxc-resolver API for per-importer tsconfig matching, or
  • deliberately depend on the same resolver package/config cache Vite uses rather than implementing another tsconfig parser.

The source rewrite must also be AST-based; string replacement would incorrectly rewrite comments, strings, and unrelated calls.

Draft status

This should not be merged as-is. The draft exists to:

  • quantify the code and performance simplification from using native Vite behavior
  • preserve executable reproductions for the remaining gaps
  • provide concrete test cases that can be ported to Vite
  • decide whether the final fix belongs entirely in Vite or needs a temporary vinext transform

@pkg-pr-new

pkg-pr-new Bot commented Jul 6, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@2546
npm i https://pkg.pr.new/create-vinext-app@2546
npm i https://pkg.pr.new/vinext@2546

commit: 8077699

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor
Example Preview Production Original
app-router-cloudflare preview production
pages-router-cloudflare preview production
app-router-playground preview production original
realworld-api-rest preview production
nextra-docs-template preview production
benchmarks preview production
hackernews preview production original
workers-cache preview production
web preview production

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared 8077699 against base 0f999d1 using alternating same-runner rounds. Next.js was unchanged and skipped.

1 improved · 0 regressed · 5 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 126.3 KB 126.3 KB ⚫ +0.0%
Client entry size (gzip) vinext 120.3 KB 120.3 KB ⚫ +0.0%
Dev server cold start vinext 2.63 s 2.64 s ⚫ +0.6%
Production build time vinext 3.15 s 3.07 s 🟢 -2.5%
RSC entry closure size (gzip) vinext 97.5 KB 97.5 KB ⚫ +0.0%
Server bundle size (gzip) vinext 164.0 KB 164.0 KB ⚫ +0.0%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

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.

1 participant