Vite
Manifest tags, the dev-server hot file, asset base URLs, prefetching and CSP nonces.
ViteAssets (a singleton, also usable directly as vite.RenderTags(httpContext, "resources/js/app.tsx")) renders the tags for the @vite(...) token and the <vite /> tag helper.
Production
In production Inertia.Net reads wwwroot/build/.vite/manifest.json (falling back to wwwroot/build/manifest.json for older Vite). It parses the manifest once and pre-renders the tags to UTF-8. For each entry it emits, in order:
<link rel="stylesheet">for the entry's CSS and the CSS of its static imports, recursively and deduplicated;<script type="module" src="...">for the entry file;<link rel="modulepreload">for each static import.
URLs are {PathBase}/{BuildDirectory}/{file} so apps under a path base work, or {AssetBaseUrl}/{file}. An entry missing from the manifest throws with the list of available entries. A missing manifest throws with the paths it looked in.
Development
While the dev server runs, the tags are @vite/client and the entry from the dev server origin, plus the React Refresh preamble for @viteReactRefresh. The dev server counts as running when:
o.Vite.DevServerUrlis set (always, in any environment), or- the environment is Development and the hot file (
wwwroot/hotby default) exists and contains the origin.
The hot file is written by your Vite config. The @inertiajs/vite plugin does not write one, so the samples include a small plugin that does.
base must differ between dev and build
Built assets are served from /build/, so the Vite base is /build/ for a build. The dev server must serve from the root because Inertia.Net emits {origin}/@vite/client and {origin}/{entry}. Use base: command === 'build' ? '/build/' : '/'.
Options
Only plain http(s) origins without quotes or markup are accepted from the hot file or DevServerUrl, because the origin is echoed into a script.
With AssetBaseUrl set, Vite's own base must match so lazily imported chunks resolve against the CDN too:
Prefetching
Page components resolved with lazy import.meta.glob are separate chunks that the browser downloads only when a page needs them. o.Vite.Prefetch downloads them after the page loads, at low priority, so the next navigation does not wait:
The tags get one small inline script with the list of chunks the entries can import later (dynamic imports, then their static imports and CSS), minus those already loaded. It is rendered once per entry set.
Content Security Policy
With a nonce-based CSP, set o.CspNonce to the request's nonce. Every script and stylesheet tag Inertia.Net writes then carries it: the page <script data-page>, the Vite tags, the React refresh preamble and the prefetch script (whose links get it too).
The nonce must be base64 or base64url; anything else throws. Cached tags are split where the nonce goes, so a nonce costs one copy of the tag bytes per request and no re-rendering.
Static assets
Use app.UseStaticFiles() with a long Cache-Control for /build/assets, or app.MapStaticAssets() when the client is built before dotnet publish. See Deploying.