Trouble with Vite + React + Vercel: SPA routing and API dev conflicts

I’m in over my head and looking for help.

I previously had a CRA + React SPA app with some redirects. A little quirky to get the redirect logic working and I needed to use proxy middleware for some cors issues, but it worked.

But CRA is old and unsupported these days and I can’t upgrade a bunch of dependencies so I migrated to Vite.

Unfortunately I’m hitting some major issues.

It kind of feels like I can get localhost working (yarn dev or vercel dev but not both), or I can get prod running but not local.

Everything works in production using vercel.json rewrites, but in local dev (vercel dev), I’m running into major issues:
• My catch-all rewrite (/(.*) → /) is needed in prod for SPA routing, but it breaks Vite’s historyApiFallback in local dev — causing errors like Manifest: SyntaxError.
• API routes like /api/c sometimes get served as static JS files, not executed, depending on the dev config.
• I’m getting conflicts between Vite’s dev server and Vercel’s dev server over who handles routing.
• Using a proxy in Vite for /api introduces other bugs when run with vercel dev.

I want:
• SPA routing to work cleanly in both dev and prod
• Serverless API routes to work locally without static conflicts

After spending over a day trying to figure it out and fix it I hit a wall. I turned to ChatGPT and used a ton of tokens in Cursor but that just ran in curcles and hit all the same issues.

If it helps, this is what ChatGPT has to say about it.

:gear: Why it breaks in Vite:

Vite uses native ES modules + Rollup + its own dev server (powered by connect), which handles routing differently:

  • Vite also supports historyApiFallback, but…
  • When you run vercel dev, Vite is no longer the top-level server — Vercel is.
  • So Vercel’s vercel.json routing logic is applied before Vite even sees the request.

:warning: The problem:

In local dev with vercel dev:

  • That catch-all rule in vercel.json (/(.*) → /) short-circuits routing before Vite can serve index.html.
  • Vite doesn’t get a chance to run its historyApiFallback, so you get weird errors like:
    “Manifest: SyntaxError: Unexpected token <”

Which usually means: you expected a .js file, but got HTML (like index.html) instead.

—-

I’m not good with all this build system stuff and redirects and honestly kind of lost. Any help would be appreciated :slight_smile:

I’m having this same issue.