Blazor’s Secret Speed: Static Web Asset in .NET 10

Blazor’s Secret Speed: Static Web Asset in .NET 10

In this post, I’ll unpack what changed for the Blazor script in .NET 10, why it matters for performance and deploys, and exactly where you should reference it across Blazor Web App, Blazor Server, and standalone Blazor WebAssembly. We’ll also cover fingerprinting, import maps, and a few easy-to-miss caveats.

What changed and why you should care

  • Static web asset: The Blazor script is now served as a static web asset rather than an embedded resource. That unlocks automatic compression and fingerprinting (stable cache-busting URLs).
  • Better caching: Fingerprinted filenames let browsers cache aggressively between releases without you worrying about invalidation.
  • Simpler story: Script locations are predictable for each hosting model and appear in your normal layout/root files.

Official docs: What’s new: Blazor script as static web assetLocation of the Blazor scriptBlazor static files.

Prerequisites

  • .NET 10 SDK and an app created with Blazor Web App, Blazor Server, or standalone Blazor WebAssembly.
  • At least one .razor file in Web App/Server projects, or set <RequiresAspNetWebAssets>true</RequiresAspNetWebAssets> in the project file.
  • If you enforce a strict CSP, plan for SRI or nonces for the inline Import Map.

Where the Blazor script lives (by app type)

The script tag appears in different files depending on your hosting model. In .NET 10, the paths below are the expected, framework-mapped static assets.

Blazor Web App

Place the script in the root App component head/body region at Components/App.razor:

HTML
<script src="_framework/blazor.web.js"></script>

Blazor Server

Reference the server script in the host page. You’ll typically see it in Pages/_Host.cshtml (or _Layout.cshtml if you structure it that way):

HTML
<script src="_framework/blazor.server.js"></script>

Standalone Blazor WebAssembly

In standalone WASM apps, the script belongs in wwwroot/index.html:

HTML
<script src="_framework/blazor.webassembly.js"></script>

Edge case: If your Web App or Server project contains no .razor files, the publish phase may skip static web assets. Opt in explicitly:

XML
<PropertyGroup>
  <RequiresAspNetWebAssets>true</RequiresAspNetWebAssets>
</PropertyGroup>

Client caching and fingerprinting

Fingerprinting bakes a content hash into filenames so browsers can cache “forever” and only re-download when content changes.

Standalone Blazor WebAssembly

  1. Enable placeholder override in your project file:
XML
<PropertyGroup>
  <OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders>
</PropertyGroup>
  1. Add import map and fingerprint marker in wwwroot/index.html:
HTML
<head>
  <script type="importmap"></script>
</head>
<body>
  <script src="_framework/blazor.webassembly#[.{fingerprint}].js"></script>
</body>

Any script with the #[.{fingerprint}] marker will be fingerprinted at build/publish. Example:

HTML
<script src="js/app#[.{fingerprint}].js"></script>

Blazor Web App (CSR)

For client-side rendering in a Blazor Web App, adopt server-side fingerprinting with MapStaticAssets, the <ImportMap /> component, and @Assets["..."] when linking CSS/JS:

HTML
<ImportMap />
<link rel="stylesheet" href="@Assets["app.css"]" />
<script type="module" src="@Assets["js/my-module.mjs"]"></script>

Optional: fingerprint additional modules in the project file:

HTML
<ItemGroup>
  <StaticWebAssetFingerprintPattern Include="JSModule" Pattern="*.mjs" Expression="#[.{fingerprint}]!" />
</ItemGroup>

Preloading framework assets

Web Apps automatically preload framework assets via HTTP Link headers. In standalone WASM, add a preload link and enable placeholder overrides:

XML
<PropertyGroup>
  <OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders>
</PropertyGroup>
HTML
<head>
  <link rel="preload" id="webassembly" />
</head>

How static asset delivery works (under the hood)

Static asset delivery with Map Static Assets

Server-side delivery uses routing endpoint conventions (MapStaticAssets) instead of Static Files middleware by default. That’s how Blazor can fingerprint, compress, and map assets like the script into _framework/.

For Blazor Web Apps, the Import Map is emitted in <head> and the resource collection is exposed to the browser so modules resolve to their fingerprinted URLs. Use @Assets["..."] to reference them in Razor.

When to still use UseStaticFiles

  • Serving files from disk that aren’t part of the build/publish pipeline.
  • Custom content-type mappings via FileExtensionContentTypeProvider.
  • Applying a path prefix to WASM assets in special hosting setups.
C#
// Avoid interfering with the Blazor script mapping
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".wasm"] = "application/wasm";
app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider });
app.UseStaticFiles(); // second call keeps framework defaults intact

Path prefix for WASM assets (Blazor Web App)

C#
endpoints.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode(options => 
        options.PathPrefix = "/path-prefix");

Static web asset base path (standalone WASM)

XML
<PropertyGroup>
  <StaticWebAssetBasePath>app1</StaticWebAssetBasePath>
</PropertyGroup>

CSP considerations

The <ImportMap> renders an inline <script>. With a strict CSP, use SRI or a nonce per the docs to avoid violations.

Troubleshooting and gotchas

  • No .razor files, missing script on publish: Add <RequiresAspNetWebAssets>true</RequiresAspNetWebAssets>.
  • Custom Static Files config breaks script: Don’t remove .js mappings or override the framework’s static mapping without a second UseStaticFiles() for defaults.
  • Non-Development testing: If you need static web assets locally in Staging, call UseStaticWebAssets() guarded by IsStaging()—never enable it unconditionally in Production.
  • ImportMap + CSP: Add SRI or a nonce to satisfy script-src.

Summary

.NET 10 moves the Blazor script to the static web assets pipeline, enabling compression and robust cache-busting. Know where to place the script per hosting model, adopt fingerprinting (standalone WASM) or @Assets/<ImportMap /> (Web Apps), and keep Static Files customizations from colliding with framework mappings. The result: faster first loads, stable updates, and fewer surprises.

Discover more from Roxeem

Subscribe now to keep reading and get access to the full archive.

Continue reading