Rendering a SPA
You mount a SPA into a Razor page with one of two tag helpers. Both render the container element your app mounts into plus the script/style tags needed to load it — one for development, one for production.
The two tag helpers
Section titled “The two tag helpers”@page@model YourApp.Pages.IndexModel@{ Layout = null;}
<dev-vite-scripts app-name="ReactApp" />@page@model YourApp.Pages.IndexModel@{ Layout = null;}
<prod-vite-scripts app-name="ReactApp" />Both helpers take a single attribute:
| Attribute | Required | Meaning |
|---|---|---|
app-name | Only when more than one app is configured | The SPA directory name to render. |
<dev-vite-scripts> — development
Section titled “<dev-vite-scripts> — development”This helper reads manifest.dev.json for the running dev server and:
- Renders the container
<div id="root">. - Loads the Vite client and your entrypoint from the dev server (
http://localhost:{port}/…), so you get hot module replacement inside the Razor page. - For React apps, injects the React refresh preamble first.
- If the dev server can’t be reached, shows a “Vite Dev Server Not Found” message and retries — so a not-yet-started dev server produces a clear hint rather than a blank page.
<prod-vite-scripts> — production
Section titled “<prod-vite-scripts> — production”This helper reads Vite’s manifest.json (for the hashed bundle paths) and manifest.prod.json
(for the container id), then:
- Emits
<link rel="stylesheet">tags for each CSS file in the entry chunk. - Emits the
<script type="module">tag for the hashed JS bundle. - Renders the container
<div>. - If no production manifest is found, shows a “Production Bundle not found” message — a reminder to
run
npm run buildor to check the configured app directory name.
Choosing between them
Section titled “Choosing between them”The two helpers are meant to be swapped per environment. A common pattern is to branch on the hosting environment in the page:
@page@model YourApp.Pages.IndexModel@inject IWebHostEnvironment Env@{ Layout = null;}
@if (Env.IsDevelopment()){ <dev-vite-scripts app-name="ReactApp" />}else{ <prod-vite-scripts app-name="ReactApp" />}For the full attribute and property surface, see the dev-vite-scripts and prod-vite-scripts references.