Skip to content

[blazor][wasm] Fix hot reload IL trimming#65903

Merged
pavelsavara merged 11 commits intomainfrom
copilot/optimize-il-trimming-blazor-wasm
Apr 7, 2026
Merged

[blazor][wasm] Fix hot reload IL trimming#65903
pavelsavara merged 11 commits intomainfrom
copilot/optimize-il-trimming-blazor-wasm

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 23, 2026

Fix hot reload IL trimming

Summary

This PR improves IL trimming effectiveness for Blazor WebAssembly apps by making the hot reload feature switch properly recognized by the IL trimmer. Previously, hot reload–related code (caches, event subscriptions, metadata update handlers) was not trimmed away in published WASM apps because the trimmer could not statically determine that MetadataUpdater.IsSupported was false.

Problem

HotReloadManager.MetadataUpdateSupported was backed by MetadataUpdater.IsSupported, which returns false at runtime in trimmed/published WASM builds. However, the IL trimmer could not prove this statically. As a result:

  • All hot reload cache-clearing event handlers were retained in trimmed output.
  • Static constructors across ~20 files registered hot reload callbacks that could never fire.
  • The HotReloadManager type itself and its dependency graph survived trimming.

Solution

  1. Introduced HotReloadManager.IsSupported — a static bool property annotated with [FeatureSwitchDefinition("System.Reflection.Metadata.MetadataUpdater.IsSupported")]. This tells the IL trimmer to substitute this property with false when the feature switch is disabled, enabling it to eliminate dead code behind the guard.

  2. Split the check into two levels:

    • HotReloadManager.IsSupported (static, trimmer-visible) — controls whether any hot reload infrastructure is linked.
    • HotReloadManager.IsEnabled (instance, runtime-mutable) — replaces the old MetadataUpdateSupported property, used for testing scenarios where hot reload behavior needs to be toggled at runtime.
  3. Updated all ~20 call sites from:

    if (HotReloadManager.Default.MetadataUpdateSupported)

    to:

    if (HotReloadManager.IsSupported)

    The static IsSupported check comes first so the trimmer can eliminate the entire if block when the feature is disabled.

  4. Updated Renderer to use the same two-level guard pattern, replacing direct references to the old static HotReloadManager.MetadataUpdateSupported.

  5. Updated ILLink substitutions in ILLink.Substitutions.xml to target the new get_IsSupported method.

Testing

  • Unit tests (RendererTest.cs): Updated to use the new IsEnabled property for controlling hot reload behavior in tests.
  • E2E test (WebAssemblyTrimmingTest.cs): Added a new test that verifies HotReloadManager type is trimmed away in published WASM builds. Uses reflection (Type.GetType) to confirm the type is absent in trimmed output.
  • Test component (HotReloadTrimmingCheck.razor): A Blazor component that checks at runtime whether HotReloadManager is present via reflection, reporting true/false.

Files changed

Core change

  • HotReloadManager.cs — Added [FeatureSwitchDefinition]-annotated IsSupported property; renamed MetadataUpdateSupported to IsEnabled.

Updated call sites (mechanical)

All files below changed from HotReloadManager.Default.MetadataUpdateSupported to HotReloadManager.IsSupported:

  • AttributeAuthorizeDataCache.cs
  • BindConverter.cs
  • ChangeDetection.cs
  • ComponentFactory.cs
  • DefaultComponentActivator.cs
  • DefaultComponentPropertyActivator.cs
  • PersistentServicesRegistry.cs
  • PersistentStateValueProviderKeyResolver.cs
  • PersistentValueProviderComponentSubscription.cs
  • ComponentProperties.cs
  • RenderHandle.cs
  • EventArgsTypeCache.cs
  • RenderTreeDiffBuilder.cs
  • Renderer.cs
  • RouteView.cs
  • RouteTable.cs
  • Router.cs
  • EndpointComponentState.cs
  • FieldIdentifier.cs
  • ExpressionFormatter.cs
  • RootTypeCache.cs
  • ExpressionMemberAccessor.cs
  • JSComponentInterop.cs

Trimmer configuration

  • ILLink.Substitutions.xml — Updated method signature from get_MetadataUpdateSupported to get_IsSupported.

Tests

  • RendererTest.cs — Updated to use IsEnabled instead of MetadataUpdateSupported.
  • WebAssemblyTrimmingTest.cs — New E2E test verifying HotReloadManager is trimmed in WASM publish.
  • HotReloadTrimmingCheck.razor — New test component for runtime type presence check.
  • Index.razor — Registered the new test component.
  • Components.TestServer.csproj — Set MetadataUpdaterSupport=true for trimmed test builds.
  • HotReloadStartup.cs — Updated to use IsEnabled.

@github-actions github-actions Bot added the area-blazor Includes: Blazor, Razor Components label Mar 23, 2026
Copilot AI requested a review from pavelsavara March 23, 2026 06:39
@pavelsavara pavelsavara added this to the .NET 11 Planning milestone Mar 23, 2026
@pavelsavara pavelsavara changed the title Use [FeatureSwitchDefinition] for hot reload guards in Renderer to enable IL trimming [blazor][wasm] Fix IL hot reload trimming Mar 24, 2026
@pavelsavara pavelsavara changed the title [blazor][wasm] Fix IL hot reload trimming [blazor][wasm] Fix hot reload IL trimming Mar 24, 2026
@pavelsavara pavelsavara marked this pull request as ready for review March 27, 2026 20:32
@pavelsavara pavelsavara requested a review from a team as a code owner March 27, 2026 20:32
Copilot AI review requested due to automatic review settings March 27, 2026 20:32
Copy link
Copy Markdown
Contributor

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 aims to improve IL trimming for Blazor WebAssembly published apps by making hot reload support trimmer-visible (via a feature-switch-based HotReloadManager.IsSupported guard), updating hot reload call sites to use a two-level guard (IsSupported + runtime-mutable IsEnabled), and adding E2E coverage to validate trimming behavior.

Changes:

  • Introduces HotReloadManager.IsSupported (feature switch) and renames the runtime toggle to HotReloadManager.Default.IsEnabled.
  • Updates hot reload cache/event-hook call sites to gate on HotReloadManager.IsSupported && HotReloadManager.Default.IsEnabled.
  • Adds a trimming check component + E2E test, and updates linker substitutions to target get_IsSupported.

Reviewed changes

Copilot reviewed 34 out of 34 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/Components/Shared/src/HotReloadManager.cs Adds IsSupported feature switch and renames runtime toggle to IsEnabled.
src/Components/Components/src/Properties/ILLink.Substitutions.xml Updates substitution to stub get_IsSupported.
src/Components/Components/src/RenderTree/Renderer.cs Makes renderer hot reload manager nullable and updates hot reload guards/registration.
src/Components/Authorization/src/AttributeAuthorizeDataCache.cs Updates hot reload cache clearing guard to new two-level check.
src/Components/Components/src/BindConverter.cs Updates formatter/parser caches’ hot reload clear hooks to new guard.
src/Components/Components/src/ChangeDetection.cs Updates hot reload cache clearing guard.
src/Components/Components/src/ComponentFactory.cs Updates hot reload cache clearing guard.
src/Components/Components/src/DefaultComponentActivator.cs Updates hot reload cache clearing guard.
src/Components/Components/src/DefaultComponentPropertyActivator.cs Updates hot reload cache clearing guard.
src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs Updates hot reload cache clearing guard.
src/Components/Components/src/PersistentState/PersistentStateValueProviderKeyResolver.cs Updates hot reload cache clearing guard.
src/Components/Components/src/PersistentState/PersistentValueProviderComponentSubscription.cs Updates hot reload cache clearing guard.
src/Components/Components/src/Reflection/ComponentProperties.cs Updates hot reload cache clearing guard.
src/Components/Components/src/RenderTree/EventArgsTypeCache.cs Updates hot reload cache clearing guard.
src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs Updates hot reload diff behavior guard to new two-level check.
src/Components/Components/src/RenderHandle.cs Updates IsRenderingOnMetadataUpdate to use the new guard.
src/Components/Components/src/Routing/Router.cs Updates hot reload route cache clearing hook guard.
src/Components/Components/src/Routing/RouteTable.cs Updates hot reload route cache clearing hook guard.
src/Components/Components/src/RouteView.cs Updates hot reload layout cache clearing hook guard.
src/Components/Endpoints/src/Rendering/EndpointComponentState.cs Updates hot reload cache clearing guard.
src/Components/Forms/src/FieldIdentifier.cs Updates hot reload cache clearing guard.
src/Components/Shared/src/RootTypeCache.cs Updates cache clear subscription/unsubscription to new guard.
src/Components/Shared/src/ExpressionFormatting/ExpressionFormatter.cs Updates hot reload cache clearing guard.
src/Components/Web/src/Forms/ExpressionMemberAccessor.cs Updates hot reload cache clearing guard.
src/Components/Web/src/JSComponents/JSComponentInterop.cs Updates hot reload cache clearing guard.
src/Components/Components/test/RendererTest.cs Updates tests to use IsEnabled and adjusts global default state handling.
src/Components/test/E2ETest/Tests/WebAssemblyTrimmingTest.cs Adds a new trimming-related E2E test.
src/Components/test/E2ETest/Infrastructure/ServerFixtures/BasicTestAppServerSiteFixture.cs Adds a flag for trimmed/multithreading execution mode to support conditional test behavior.
src/Components/test/E2ETest/ServerExecutionTests/HotReloadTest.cs Skips hot reload test in trimmed/multithreading mode.
src/Components/test/testassets/BasicTestApp/HotReloadTrimmingCheck.razor Adds runtime reflection checks for hot reload type/method presence.
src/Components/test/testassets/BasicTestApp/Index.razor Registers the new trimming check component in the test app UI.
src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj Adds MetadataUpdaterSupport property for test configurations.
src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs Updates startup to enable hot reload via IsEnabled.
src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj Adds MetadataUpdaterSupport property for test server configuration.

Comment thread src/Components/Components/src/RenderTree/Renderer.cs
Comment thread src/Components/Components/src/RenderTree/Renderer.cs Outdated
Comment thread src/Components/Shared/src/HotReloadManager.cs
Comment thread src/Components/test/E2ETest/Tests/WebAssemblyTrimmingTest.cs
Comment thread src/Components/test/E2ETest/ServerExecutionTests/HotReloadTest.cs
Comment thread src/Components/Components/src/RenderTree/Renderer.cs
Comment thread src/Components/Components/src/RenderTree/Renderer.cs Outdated
Comment thread src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
Comment thread src/Components/Components/src/RenderTree/Renderer.cs Outdated
@pavelsavara pavelsavara requested a review from tmat March 31, 2026 12:54
Comment thread src/Components/Shared/src/HotReloadManager.cs Outdated
@pavelsavara pavelsavara requested a review from tmat April 1, 2026 15:47
@pavelsavara pavelsavara merged commit 309d909 into main Apr 7, 2026
25 checks passed
@pavelsavara pavelsavara deleted the copilot/optimize-il-trimming-blazor-wasm branch April 7, 2026 06:14
javiercn added a commit that referenced this pull request Apr 11, 2026
…hesis

- Enable Chrome performance logging to capture HTTP status codes and
  MIME types for network requests on assertion failure
- Include browser URL and filtered network response details
  (_framework, _blazor, 4xx/5xx) in BrowserAssertFailedException
- Skip verbose performance logs from routine after-test log dump
- Set MetadataUpdaterSupport=false in BasicTestApp.csproj to test
  hypothesis that PR #65903 change causes intermittent MIME type
  failures for dotnet.js in E2E tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
javiercn added a commit that referenced this pull request Apr 11, 2026
…hesis

- Enable Chrome performance logging to capture HTTP status codes and
  MIME types for network requests on assertion failure
- Include browser URL and filtered network response details
  (_framework, _blazor, 4xx/5xx) in BrowserAssertFailedException
- Skip verbose performance logs from routine after-test log dump
- Set MetadataUpdaterSupport=false in BasicTestApp.csproj to test
  hypothesis that PR #65903 change causes intermittent MIME type
  failures for dotnet.js in E2E tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants