A stale vite.config.js silently overrode my vite.config.ts

1 min read ViteTypeScript

Edits to vite.config.ts had no effect because a compiled vite.config.js sat next to it, and Vite loads the .js in preference to the .ts.

The symptom

I edited vite.config.ts, saved, restarted the dev server, and nothing changed. Added an alias: ignored. Changed a plugin option: ignored. The config file looked correct and was clearly the one Vite should be reading, yet every edit behaved as if the file were read-only.

What was actually happening

The project used TypeScript project references and built with tsc -b. That command does not just type-check, it emits. So tsc -b compiled vite.config.ts into a sibling vite.config.js (plus a vite.config.d.ts) right next to the source.

Vite resolves its config by extension priority, and vite.config.js wins over vite.config.ts. Once that emitted .js existed (and worse, once it got committed), Vite loaded the stale compiled copy and ignored every edit I made to the .ts. The .js only regenerated when tsc -b ran again, so my live edits never reached the bundler.

You can confirm it in one line:

ls vite.config.*
# vite.config.ts   vite.config.js   vite.config.d.ts   <- the .js is the one Vite loads

The fix

Stop committing the emitted artifacts and let them stay out of the way. tsc -b regenerates them each build, so they never need to live in git:

# .gitignore
vite.config.js
vite.config.d.ts

Then delete the tracked copies once so the stale files are gone:

git rm --cached vite.config.js vite.config.d.ts
rm vite.config.js vite.config.d.ts

With the compiled sibling removed, Vite falls back to vite.config.ts, and edits take effect immediately again.

The lesson

When config edits seem to “do nothing,” look for a compiled sibling file that takes precedence. A build step that emits next to your source can quietly shadow the file you are editing.

Share: X Hacker News Reddit

Related fixes