Skip to content

Fix serving of blazor.web.js and blazor.server.js under the original static assets model #66059

@NetherGranite

Description

@NetherGranite

Summary

.NET 10 made .MapStaticAssets() the only way to serve blazor.server.js and blazor.web.js even though blazor.webassembly.js is served just fine without it. When using .UseStaticFiles(), the new .AddInteractiveServerComponents() and the old .MapBlazorHub() no longer result in those files being served. This is what #64381 reports.

Motivation and goals

This removes the unnecessary overhead of being forced to migrate to .MapStaticAssets() when migrating to .NET 10. It also solves the significant headache of discovering that this is the solution to an obscure error in the first place. For example, I personally had to do a lot of research to understand how this would impact my custom Webpack pipeline.

In scope

Out of scope

Risks / unknowns

This restores half-deleted functionality (only the server side) and without clear guidance as to how to adapt without having to search through GitHub issues. I don't believe this is a risk or blocker for future features.

Examples

In the following examples, .MapStaticAssets() is NOT called, and it's assumed that .UseRouting() is called before .UseStaticFiles() so that the static files middleware is endpoint-aware. The following no longer works in .NET 10:

app.UseStaticFiles();
app.MapRazorComponents().AddInteractiveServerComponents();
app.UseStaticFiles();
app.MapBlazorHub();

But these still do:

app.UseStaticFiles();
app.MapRazorComponents().AddInteractiveWebAssemblyComponents();
app.UseStaticFiles();
app.UseBlazorFrameworkFiles();

Both should work.

Research

This issue appears to be a mistake, not an intentional change. Here's the timeline I discovered:

  1. The static asset guard is introduced to only the wasm endpoints. It is never added to the server endpoints. See: [Blazor] Adds compresion support for all assets in an application #55558
  2. The static asset guard is changed from if (wasmWithOptions is { EndpointOptions.ConventionsApplied: true }) to if (applicationBuilder.Properties[ResourceCollectionKey] is ResourceAssetCollection assetMap). See: [Blazor] Consume fingerprinted assets in MVC and Blazor #56045
  3. At some point, the unified endpoint blazor.web.js is added into the mix. See: Streaming SSR: DOM updating #47605
  4. Add package for consuming Blazor framework assets #58721 implements the switch to serving blazor.*.js files as static assets. In the same batch of changes, however, the server endpoints are just dropped entirely. Presumably this made sense without the context of this papertrail.

Detailed design

Given the evidence, I believe the correct (and very simple) fix is to re-add the server and unified endpoints (blazor.server.js and blazor.web.js), but under the same guard as the wasm endpoints. This was likely the correct course of action to begin with when looking at the big picture.

Key decisions

  • Since the old versions of the endpoints read from embedded resources, the new versions will instead mimic how the wasm endpoints are read from static files.
  • The old versions returned the map files for the blazor.*.js files guarded by #if DEBUG for internal testing purposes. Given that they were removed and probably are configured to exist as static assets for internal testing, these will not be added back.
  • The wasm endpoints have very elaborate static files options, whereas the server and unified endpoints had very basic ones. My research showed that this was not the unified and server endpoints falling behind; rather, the requirements for them were considerably more simple since they're singular JS files. This will be preserved.
  • There are slight inconsistencies between the endpoint configuration for blazor.server.js and blazor.web.js. These will be preserved.
  • blazor.web.js received a feature improvement that makes it configurable e.g. with [AllowAnonymous], but the same improvement was not made to blazor.server.js even though it existed at the time. This will be preserved. See: [Blazor] Add Blazor Web Endpoints to the endpoint data source #57086

Open questions

  • I am not sure what the right way to get whether static assets are active/present to the endpoint builder helpers. I have left these as TODOs. I am a bit suspicious of the current pattern that almost seems to hijack the app builder properties in order to communicate across route config calls, and even that comes after scraping the result of static assets config off an arbitrary endpoint.

Draft implementation

This is a relatively simple change to a system that's a bit of a maze, so I figured a simple draft PR would help get the ideas across. The PR is broken up into digestible commits. See: #66060

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-blazorIncludes: Blazor, Razor Componentsdesign-proposalThis issue represents a design proposal for a different issue, linked in the description

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions