tsconfig aliases
TypeScript’s compilerOptions.paths lets you write import App from "@/App" instead of import App from "../../App". Vite doesn’t read that out of the box — without help, your TS compiles but the dev server reports “module not found”. @mongez/vite reads tsconfig.json and mirrors paths into resolve.alias so the two agree.
Default behaviour
mongezVite(); // linkTsconfigPaths: true, tsconfigAlias: true{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"], "components/*": ["src/components/*"], "lib": ["src/lib/index.ts"] } }}After the config hook runs, config.resolve.alias is:
[ { find: "@", replacement: "<cwd>/src" }, { find: "components", replacement: "<cwd>/src/components" }, { find: "lib", replacement: "<cwd>/src/lib/index.ts" },]Now both tsc and Vite resolve:
import App from "@/App"; // → <cwd>/src/Appimport Button from "components/Button"; // → <cwd>/src/components/Buttonimport { foo } from "lib"; // → <cwd>/src/lib/index.tsHow the transform works
For each [find, value] entry in compilerOptions.paths:
findhas its trailing/*stripped ("@/*"→"@").valueis read asString(value)— for a single-element array["src/*"]this gives"src/*". Its trailing/*is also stripped.- The replacement is run through
path.resolve(process.cwd(), ...)to produce an absolute path.
{ find: "@", replacement: path.resolve(process.cwd(), "src"),}Opting out
Set linkTsconfigPaths: false to skip:
mongezVite({ linkTsconfigPaths: false });Use this when:
- You already use
vite-tsconfig-pathsor another plugin that does the same thing. - You want to define
resolve.aliasby hand invite.config.ts. - Your
tsconfig.jsonpathsdon’t translate cleanly (the transform is intentionally simple — see “Gotchas”).
No-overwrite semantics
If you already declared resolve.alias in vite.config.ts, the plugin does not touch it:
export default defineConfig({ resolve: { alias: { "@": "/elsewhere" }, }, plugins: [mongezVite()],});// → resolve.alias stays { "@": "/elsewhere" }, even though tsconfig has// "@/*": ["src/*"]This is intentional — explicit config beats inferred config.
When the plugin does nothing
linkTsconfigPaths: false.tsconfigAlias: false(separate but tied option — both must be truthy).tsconfig.jsondoesn’t exist inprocess.cwd().tsconfig.jsonexists butcompilerOptions.pathsis missing or empty.config.resolve.aliasis already set by the user.
Gotchas
- Only the first array entry survives — the transform reads
String(value)rather than iterating. For"foo/*": ["src/foo/*", "lib/foo/*"], only the join-form is read. Most setups only have one entry per key, so this is rarely a problem. /*is stripped exactly once — the transform calls.replace("/*", "")(first occurrence). Nested globs like"foo/*/*"would have only the first/*stripped.- No
extends-following. If yourtsconfig.jsonextends a base config, the plugin reads only the top file. Re-declare yourpathsat the top level or wire it differently. baseUrlis ignored. The transform always resolves againstprocess.cwd(). If yourpathsare written relative to a differentbaseUrl, the resulting aliases won’t match.- Windows path separators.
path.resolveuses native separators (\on Windows). Vite handles both, so this isn’t user-visible — but tests that string-match the replacement need to normalise.