v0.1.0  ·  Vite 8  ·  MIT

Vite multi-page apps,
without the 404s

Vite ignores your HTML entry keys and returns 404s on clean URLs. One plugin. Zero config. Dev routing and build output fixed together.

$ npm install -D mpa-vite-plugin
→ view on github
before
pages/
  index/
    index.html
  about/
    index.html ← 404
dist/src/pages/about/
  index.html ← wrong path
mpa-vite-plugin
after
src/pages/
  index/index.html
  about/index.html
localhost:5173/about
dist/about.html
auto-discovered, no config
import multivite from 'mpa-vite-plugin'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [multivite()] // that's it
})
setup

get started in three steps

Works with any create-vite project — vanilla-ts, react-ts, or anything else.

01
install the plugin
$ npm install -D mpa-vite-plugin
02
add to vite.config.ts
import multivite from 'mpa-vite-plugin'
export default defineConfig({ plugins: [multivite()] })
03
update your dev script
Vite requires --configLoader runner to resolve locally installed plugins correctly.
"dev": "vite --configLoader runner"
Without this flag the dev server will fail to find the plugin. Build (vite build) is unaffected.
internals

three hooks, nothing else

No separate processes, no port juggling, no proxy. The plugin hooks into Vite's existing lifecycle. ~100 lines of TypeScript.

01
config
Globs src/pages/ and injects all HTML files as Rollup entry points. No manual listing needed.
02
configureServer
Adds a middleware that rewrites /about to the correct HTML before Vite sees the request. HMR works untouched.
03
generateBundle
Moves output files from their deep source paths to a clean flat dist/ at build time.
community

what people are saying

I've been manually patching vite.config.js for two projects now. Dropped this in and it just worked.

frontend dev · Berlin

The output path bug has been open in Vite for over a year. Glad someone fixed it at the plugin level.

staff engineer

Astro is overkill when you just want HTML, CSS, and TypeScript. This fills the exact gap.

indie dev

Three hooks, ~100 lines of TypeScript. Read the source in five minutes. This is what a good plugin looks like.

open source contributor
reference

vite multi-page app, explained

Common questions about MPA routing in Vite and how this plugin addresses them.

Why does Vite return 404 on /about?

Vite's dev server only routes to pages at their exact file paths. It doesn't know to map /about to src/pages/about/index.html. This plugin inserts a middleware that rewrites the URL before Vite handles the request.

Why is the build output path wrong?

Vite ignores entry key names for HTML files and uses the resolved file path instead. The plugin's generateBundle hook remaps paths to a clean flat structure.

Do I need to list my pages manually?

No. The plugin globs src/pages/ recursively. Add a new folder with an index.html and it's automatically included in dev and build.

Does HMR still work?

Yes. Single Vite instance, single HMR websocket. No per-page processes, no proxy, no coordination. It works exactly as in a standard Vite project.

What about Astro or Parcel?

Astro requires a new mental model. Parcel has the same dev routing problem. This plugin is just Vite — your existing config, your existing tooling, your existing knowledge.

Works with React or Vue?

Yes. Framework-agnostic. Works alongside @vitejs/plugin-react, @vitejs/plugin-vue, or any other Vite plugin.