Skip to content

feat: support opt-in tsconfigPaths #427

Merged
pi0 merged 7 commits into
unjs:mainfrom
rexxars:feat/ts-paths
Feb 27, 2026
Merged

feat: support opt-in tsconfigPaths #427
pi0 merged 7 commits into
unjs:mainfrom
rexxars:feat/ts-paths

Conversation

@rexxars

@rexxars rexxars commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

Resolves TypeScript compilerOptions.paths aliases at runtime, matching tsc behavior.

Resolves #373

Usage

const jiti = createJiti(import.meta.url, { tsconfigPaths: true });
  • true - auto-discover tsconfig.json by walking up from the jiti instance's parent path
  • string - explicit path to a tsconfig.json
  • false (default) - disabled (backwards compatible)

Also configurable via JITI_TSCONFIG_PATHS environment variable.

Implementation

Uses get-tsconfig (same library used by tsx and bundle-require) to parse the tsconfig and create a paths matcher. The matcher is created once per jiti instance, not re-parsed on every resolve call.

In the resolve chain (resolve.ts), tsconfig path candidates are tried before alias resolution and before Node's native resolution. Each candidate is resolved through jiti's existing file resolution (including extension handling), and the
first that exists on disk wins.

Handles the full tsc path matching spec:

  • Wildcard patterns (@/*./src/*)
  • Exact matches (@config./src/config)
  • Catch-all (*./types/*)
  • Mid-pattern wildcards (foo/*/bar./src/*/baz)
  • Multiple fallback targets (@/*./src/*, ./generated/*) - tries each in order
  • extends chains and baseUrl resolution (handled by get-tsconfig)

Edge cases:

  • No tsconfig found → silent no-op
  • No paths in tsconfig → skip resolution
  • Both tsconfigPaths and alias set → tsconfig paths run first, then alias as a second pass

Aside

Really happy with jiti - it handles compatibility better than both tsx and bundle-require - the only thing missing is TS paths support :)

Let me know if you need something to change! I ran into an issue when running tests locally that I attempted to fix in #426

Summary by CodeRabbit

  • New Features
    • Added a public option to enable TypeScript path-alias resolution (boolean or string); supports auto-discovery or explicit tsconfig path and respects JITI_TSCONFIG_PATHS.
  • Documentation
    • README updated with usage, types, and environment variable details.
  • Types
    • Public types updated to include the new option and related context capability.
  • Tests
    • Added fixture demonstrating resolving modules via tsconfig path aliases.

Comment thread lib/types.d.ts
@coderabbitai

coderabbitai Bot commented Feb 27, 2026

Copy link
Copy Markdown

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

📥 Commits

Reviewing files that changed from the base of the PR and between 8551430 and 31a0119.

📒 Files selected for processing (1)
  • src/options.ts
 ____________________________________________
< `undefined` is not a business requirement. >
 --------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).

✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.

Tip

You can disable poems in the walkthrough.

Disable the reviews.poem setting to disable the poems in the walkthrough.

📝 Walkthrough

Walkthrough

Adds an opt-in tsconfigPaths option (default false) to enable resolving TypeScript paths via get-tsconfig. Resolution is lazily initialized, exposed on the runtime context as resolveTsConfigPaths, and consulted before existing alias handling during module resolution.

Changes

Cohort / File(s) Summary
Documentation & Types
README.md, lib/types.d.ts, src/types.ts
Document new tsconfigPaths option; add `tsconfigPaths: boolean
Options & Defaults
src/options.ts
Introduce tsconfigPaths option defaulting to false, sourced from JITI_TSCONFIG_PATHS.
Core Loader Runtime
src/jiti.ts
Normalize file:// filenames, lazily load get-tsconfig when enabled, build a paths matcher, and attach resolveTsConfigPaths to loader context.
Module Resolution Logic
src/resolve.ts
Pre-alias resolution: if ctx.resolveTsConfigPaths exists and not skipped, query candidates and attempt recursive resolution (guarded to avoid re-entry).
Dependencies
package.json
Add get-tsconfig@^4.13.6 to dependencies/devDependencies.
Test Fixtures
test/fixtures/tsconfig-paths/*
Add fixture demonstrating TS path aliases: index.mjs, src/config.ts, and tsconfig.json mapping ~/*./*.

Sequence Diagram(s)

sequenceDiagram
  participant App as App (consumer)
  participant Jiti as Jiti Loader
  participant Resolve as jitiResolve
  participant TSFinder as get-tsconfig
  participant FS as Filesystem

  App->>Jiti: import "alias/path"
  Jiti->>Resolve: jitiResolve(id)
  Resolve->>Jiti: checks ctx.resolveTsConfigPaths?
  alt tsconfigPaths enabled
    Jiti->>TSFinder: discover/parse tsconfig (lazy)
    TSFinder->>FS: read tsconfig.json
    TSFinder-->>Jiti: paths candidates[]
    Jiti->>Resolve: try each candidate (recursive resolve, skip re-entry)
    Resolve->>FS: resolve candidate -> file path
    Resolve-->>Jiti: resolved path
  end
  Resolve->>FS: fallback to alias/normal resolution
  Resolve-->>Jiti: module file path
  Jiti-->>App: return module
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I followed maps in hidden files,
A lazy hop through parent piles.
Paths revealed, aliases sing,
Resolver found the missing string.
Cheers — the loader learned to smile.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: support opt-in tsconfigPaths' accurately and concisely describes the main feature addition.
Linked Issues check ✅ Passed The implementation fully addresses issue #373 by adding an opt-in tsconfigPaths option that defaults to false and resolves TypeScript path aliases when enabled.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the tsconfigPaths feature with no unrelated modifications present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pi0 pi0 changed the title feat: support typescript paths feat: support opt-in tsConfigPaths Feb 27, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/jiti.ts (1)

52-65: Avoid non-null assertion when createPathsMatcher can return null.

createPathsMatcher returns null when no paths are defined in the tsconfig. Using ! on line 63 bypasses TypeScript's null check but assigns null to a variable typed as (...) | undefined. While this works at runtime (both are falsy), it's misleading and could cause issues if the type is relied upon elsewhere.

♻️ Proposed fix
   const tsconfig = getTsconfig(searchPath);
   if (tsconfig) {
-    resolveTsConfigPaths = createPathsMatcher(tsconfig)!;
+    resolveTsConfigPaths = createPathsMatcher(tsconfig) ?? undefined;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/jiti.ts` around lines 52 - 65, The code currently uses a non-null
assertion on createPathsMatcher(tsconfig) when initializing
resolveTsConfigPaths; instead call createPathsMatcher(tsconfig) into a temporary
(e.g., matcher) and only assign to resolveTsConfigPaths if matcher is non-null,
removing the "!" so resolveTsConfigPaths remains undefined when
createPathsMatcher returns null; update the block where getTsconfig and
createPathsMatcher are used (symbols: resolveTsConfigPaths, createPathsMatcher,
getTsconfig, opts.tsconfigPaths, filename) accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@package.json`:
- Line 110: The package currently lists "get-tsconfig" only under
devDependencies but src/jiti.ts requires it at runtime when the tsconfigPaths
option is enabled; move the "get-tsconfig" entry from devDependencies into
dependencies in package.json so production installs include it, ensuring the
runtime require in src/jiti.ts (the code that references get-tsconfig when
tsconfigPaths is true) will not throw a "Cannot find module" error.

In `@src/options.ts`:
- Line 30: The tsconfigPaths option currently calls _jsonEnv<boolean |
string>("JITI_TSCONFIG_PATHS", false) which JSON.parse()s the env value and
silently falls back to false for plain path strings; update the handling so
JITI_TSCONFIG_PATHS accepts either a JSON boolean or a plain string path: modify
the logic used for tsconfigPaths (replace or wrap the call to _jsonEnv) to try
JSON.parse but on parse failure return the raw string value (or the default
false if the env is empty), preserving types boolean | string and ensuring
tsconfigPaths and _jsonEnv/JITI_TSCONFIG_PATHS references reflect this behavior.

---

Nitpick comments:
In `@src/jiti.ts`:
- Around line 52-65: The code currently uses a non-null assertion on
createPathsMatcher(tsconfig) when initializing resolveTsConfigPaths; instead
call createPathsMatcher(tsconfig) into a temporary (e.g., matcher) and only
assign to resolveTsConfigPaths if matcher is non-null, removing the "!" so
resolveTsConfigPaths remains undefined when createPathsMatcher returns null;
update the block where getTsconfig and createPathsMatcher are used (symbols:
resolveTsConfigPaths, createPathsMatcher, getTsconfig, opts.tsconfigPaths,
filename) accordingly.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c49c54e and 636ff3d.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • test/__snapshots__/fixtures.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (10)
  • README.md
  • lib/types.d.ts
  • package.json
  • src/jiti.ts
  • src/options.ts
  • src/resolve.ts
  • src/types.ts
  • test/fixtures/tsconfig-paths/index.mjs
  • test/fixtures/tsconfig-paths/src/config.ts
  • test/fixtures/tsconfig-paths/tsconfig.json

Comment thread package.json
Comment thread src/options.ts Outdated
@pi0 pi0 changed the title feat: support opt-in tsConfigPaths feat: support opt-in tsconfigPaths Feb 27, 2026
autofix-ci Bot and others added 2 commits February 27, 2026 13:04
add rawFallback param to _jsonEnv to return raw env value on JSON.parse failure

@pi0 pi0 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks ❤️

@pi0 pi0 merged commit 3ce2426 into unjs:main Feb 27, 2026
1 check was pending
@rexxars

rexxars commented Mar 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for merging! Any chance of a new release anytime soon? Hope to release something depending on this and would rather not use a fork :)

@pi0

pi0 commented Mar 3, 2026

Copy link
Copy Markdown
Member

surely soon. please ping me by this week if forgot.

@rexxars rexxars deleted the feat/ts-paths branch March 3, 2026 19:12
@rexxars

rexxars commented Mar 9, 2026

Copy link
Copy Markdown
Contributor Author

@pi0 Ping as requested ;)

@rexxars

rexxars commented Mar 20, 2026

Copy link
Copy Markdown
Contributor Author

Hate to keep pinging, but wondering if there's any chance of a new release @pi0 ?

@jsardev

jsardev commented Apr 8, 2026

Copy link
Copy Markdown

Would be great to have this released 🙏 Can't wait!

@pi0

pi0 commented May 5, 2026

Copy link
Copy Markdown
Member

Hi. Sorry for delay it is out! https://github.com/unjs/jiti/releases/tag/v2.7.0

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.

Add feature flag to support typescript paths

4 participants