Skip to content

[wasm] General HotReload agent for WebAssembly in browser #49800

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

maraf
Copy link
Member

@maraf maraf commented Jul 16, 2025

Extract HotReload agent from Blazor to a general purpose HotReload for WebAssembly in browser scenarios.

The goal is to enable HotReload in non-Blazor scenarios.

The package is implicitly referenced by WasmSDK and can be turned off with WasmEnableHotReload=false. We are always referencing "current" version and for downlevel we need to multitarget.

The package contains a module that is recognized by WasmSDK and automatically loaded. The module then instructs Mono runtime that HotReload is enabled and provides callbacks migrated from Blazor internal JS API that are used by aspnetcore-browser-refresh.js. Before the built-in HotReload in Blazor gets removed, the module also disables it.

Migration from Blazor

  • WebAssemblyHotReload.cs -> aspnetcore/WebAssemblyHotReload.cs
    • Instead of just Blazor specific JavaScript interop we have migrated to the source generated one from runtime that is usable in all .NET on WASM apps. We need to do JSON serialization manually, because the interop layer doesn't do it automatically.
  • Microsoft.DotNet.HotReload.WebAssembly.Browser.lib.module.js -> aspnetcore/Boot.WebAssembly.Common.ts
    • Standard esmodule supported by WasmSDK, the other part of JS interop changes and check for browser refresh script

Contributes to dotnet/aspnetcore#61272
Related to dotnet/aspnetcore#62735

@maraf maraf added this to the 10.0.1xx milestone Jul 16, 2025
@maraf maraf self-assigned this Jul 16, 2025
@github-actions github-actions bot added the Area-AspNetCore RazorSDK, BlazorWebAssemblySDK, dotnet-watch label Jul 16, 2025
Copy link
Contributor

Thanks for your PR, @@maraf.
To learn about the PR process and branching schedule of this repo, please take a look at the SDK PR Guide.

@maraf maraf marked this pull request as ready for review July 16, 2025 11:53
@Copilot Copilot AI review requested due to automatic review settings July 16, 2025 11:53
@maraf maraf requested review from tmat, a team, lewing, akoeplinger and pavelsavara as code owners July 16, 2025 11:53
@maraf maraf requested a review from javiercn July 16, 2025 11:53
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR extracts the HotReload agent from Blazor to create a general-purpose HotReload capability for WebAssembly browser scenarios. The goal is to enable HotReload functionality in non-Blazor WebAssembly applications.

Key changes include:

  • Adding implicit HotReload package reference in WasmSDK for .NET 10+ projects
  • Creating a new WebAssembly-specific HotReload agent that can work independently of Blazor
  • Implementing JavaScript interop for runtime configuration and delta application

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/WasmSdk/Sdk/Sdk.targets Adds implicit package reference for HotReload with conditional enablement logic
src/BuiltInTools/dotnet-watch.slnf Includes new HotReload WebAssembly project in solution filter
wwwroot/Microsoft.DotNet.HotReload.WebAssembly.Browser.lib.module.js JavaScript module for runtime configuration and Blazor API compatibility
WebAssemblyHotReload.cs Core C# implementation handling delta application and HTTP communication
Microsoft.DotNet.HotReload.WebAssembly.Browser.csproj Project file for new HotReload package
sdk.slnx Adds new project to main solution
Comments suppressed due to low confidence (2)

src/BuiltInTools/HotReloadAgent.WebAssembly.Browser/WebAssemblyHotReload.cs:109

  • [nitpick] The variable name 'i' is not descriptive. Consider renaming it to 'updateIndex' or 'currentUpdate' to improve code readability.
                var i = 1;

src/BuiltInTools/HotReloadAgent.WebAssembly.Browser/WebAssemblyHotReload.cs:147

  • The variable name 'jsonContext' does not follow C# naming conventions for private static readonly fields. It should be 's_jsonContext' to match the pattern used elsewhere in this class.
    private static readonly WebAssemblyHotReloadJsonSerializerContext jsonContext = new(new(JsonSerializerDefaults.Web));

@maraf maraf changed the title [wasm] General HotReload agent for WebAssembly [wasm] General HotReload agent for WebAssembly in browser Jul 16, 2025
Copy link
Member

@tmat tmat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Someone should review the WasmSdk change. Looks reasonable but I can't tell if there are any undesirable side effects.


<Import Project="..\HotReloadAgent\Microsoft.DotNet.HotReload.Agent.projitems" Label="Shared" />
<Import Project="..\HotReloadAgent.Data\Microsoft.DotNet.HotReload.Agent.Data.projitems" Label="Shared" />

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider making the initializer apply only at build time. (There's no need to bring that initializer into the published payload) (AssetKind=Build)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We won't win that much. The assembly will still get loaded and we can't make it lazy, because JSExport doesn't work if we load the assembly lazily.

Comment on lines 24 to 28
<Target Name="_ImplicitlyReferenceHotReload" BeforeTargets="ProcessFrameworkReferences">
<ItemGroup Condition="'$(_WasmEnableHotReload)' == 'true'">
<PackageReference Include="Microsoft.DotNet.HotReload.WebAssembly.Browser" Version="$(NETCoreSdkVersion)" />
</ItemGroup>
</Target>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this get trimmed away?

An alternative would be not having a package at all and instead inject the dll and the initializer in a target as part of the build. AFAIK, it doesn't even need to be part of the compilation, does it?

As long as we tell the wasm runtime to load the dll when we are bootstrapping the framework we should be good, shouldn't we?

Copy link
Member Author

@maraf maraf Jul 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The challenge is how to know that there is a .NET somewhere in the browser.

We would have to read something from global namespace in the runtime to check if hot reload is attached. The other challenge would be to correctly select the assembly from multi-targeting.
It's possible..

The package is referenced only in non-Release Debug builds, that's how it gets trimmed.

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small suggestions, but overall looks good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-AspNetCore RazorSDK, BlazorWebAssemblySDK, dotnet-watch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants