How It Works
The central design idea in Vite.NET is that the front end describes itself to the back end through manifest files. The back end’s only configuration is the directory name of each app; every other value flows from a manifest the Vite plugin generates.
This page explains the data flow so the tag helpers and configuration make sense.
The problem manifests solve
Section titled “The problem manifests solve”To render a SPA into a Razor page, the back end needs to know a few things:
- The entrypoint module (e.g.
src/main.tsx). - The container element id the app mounts into (e.g.
root). - Whether the app is React (React needs an extra HMR preamble in development).
- In development, the port the Vite dev server is listening on.
- In production, the hashed filenames Vite produced for the JS and CSS.
Older integrations made you hand-write most of these in appsettings.json and keep them in sync
with vite.config.ts. Vite.NET instead has the plugin emit them, so there is a single source
of truth: your Vite config.
The two manifests
Section titled “The two manifests”The plugin writes a different manifest depending on the mode.
Development — manifest.dev.json
Section titled “Development — manifest.dev.json”When you run vite (the dev server), the plugin waits for the server to start listening, then
writes wwwroot/{AppFolder}/manifest.dev.json:
{ "port": 5173, "entrypoint": "src/main.tsx", "containerElementId": "root", "isReact": true}The <dev-vite-scripts> tag helper reads this to know which port to load the Vite client and
entrypoint from, and how to mount the app.
Production — manifest.prod.json
Section titled “Production — manifest.prod.json”When you run vite build, the plugin emits manifest.prod.json into the build output, next to
Vite’s own hashed manifest.json:
{ "entrypoint": "src/main.tsx", "containerElementId": "root", "isReact": true}Production needs no port — the assets are served statically. The <prod-vite-scripts> tag helper
combines this integration metadata with Vite’s standard manifest.json (which maps your
entrypoint to its hashed output files) to render the final tags.
End-to-end flow
Section titled “End-to-end flow”-
You configure the plugin in
vite.config.tswith your entrypoint and container id:ViteDotNetPlugin('src/main.tsx', 'root') -
The plugin derives the app folder name from the working directory (e.g.
ReactApp) and detects React from the resolved plugin list. -
On
npm run dev, the plugin writesmanifest.dev.json. Onnpm run build, it writes the production bundle plusmanifest.prod.json, both intowwwroot. -
The back end reads the app folder name from the
ViteDotNetconfig section and locates the manifests underwwwroot/{AppFolder}/. -
A tag helper renders the SPA into a Razor page —
<dev-vite-scripts>in development,<prod-vite-scripts>in production.
Why the output goes into wwwroot
Section titled “Why the output goes into wwwroot”The plugin sets Vite’s build.outDir to ../wwwroot/{AppFolder}, so compiled assets land inside your
ASP.NET Core project’s static-files directory. This is what lets your .NET app serve the SPA’s
assets directly — no separate Node server, no proxy. Each app builds into its own folder, so
emptyOutDir only ever clears that app’s assets and several SPAs can share one wwwroot without
overwriting each other.
Next steps
Section titled “Next steps”- The Vite Plugin — what the plugin configures and detects.
- Backend Configuration — the
ViteDotNetsection in depth. - Rendering a SPA — the two tag helpers, side by side.