Skip to content

WebAssembly Out-of-Process Renderer#66442

Open
pavelsavara wants to merge 9 commits intodotnet:mainfrom
pavelsavara:wasm_render_distance
Open

WebAssembly Out-of-Process Renderer#66442
pavelsavara wants to merge 9 commits intodotnet:mainfrom
pavelsavara:wasm_render_distance

Conversation

@pavelsavara
Copy link
Copy Markdown
Member

@pavelsavara pavelsavara commented Apr 23, 2026

WebAssembly Out-of-Process Renderer

Summary

Introduces a new WebAssembly rendering mode that serializes render batches to a binary byte[] and passes them to JavaScript via JSImport, instead of sharing raw pointers into the .NET managed heap. This decouples the C# and JS heaps, eliminating the need for a heap lock during rendering and paving the way for future Web Worker isolation.

Current Flow (Shared-Memory Renderer)

C# Renderer produces RenderBatch (struct)
       |
       v
WebAssemblyRenderer passes void* pointer via synchronous JSImport
       |
       v
JS acquires WASM heap lock (prevents GC)
       |
       v
SharedMemoryRenderBatch reads struct fields by hardcoded byte offsets directly from WASM heap
       |
       v
BrowserRenderer applies DOM edits
       |
       v
JS releases heap lock

Problems: Requires heap lock that freezes all .NET execution during DOM patching. Struct field offsets are brittle. Cannot move .NET to a Web Worker because JS and C# must share an address space.

New Flow (Out-of-Process Renderer)

C# Renderer produces RenderBatch (struct)
       |
       v
WebAssemblyRenderer serializes via RenderBatchWriter -> byte[]
(same binary format as Blazor Server, with UTF-16LE string table optimization)
       |
       v
JSImport passes byte[] as Uint8Array to JS (self-contained copy, no heap dependency)
       |
       v
OutOfProcessRenderBatch parses the byte[] (same class used by Server rendering)
       |
       v
BrowserRenderer applies DOM edits (no heap lock needed)

Benefits: No heap lock. Self-contained batch data. Reuses Server's proven serialization path. UTF-16LE string table avoids double UTF-8 transcoding (C# and JS are both natively UTF-16). Future-proof for Web Worker isolation.

What Changed

New Files

File Purpose
OOPRendererInteractivity.razor Test page covering clicks, text binding, JS interop, conditional rendering, and list rendering
WebAssemblyOOPRendererTest.cs E2E tests validating the OOP renderer across multiple interaction patterns
OOPRendererServerFixture.cs Test fixture that enables the OOP renderer via --EnableOOPRenderer=true

Modified Files

File Change
WebAssemblyRenderer.cs Added useOutOfProcessRendering constructor flag; OOP path serializes via RenderBatchWriter and calls RenderBatchOOP JSImport
RenderBatchWriter.cs Added WriteStringTableUtf16() for UTF-16LE string table encoding; new constructor flag useUtf16StringTable
OutOfProcessRenderBatch.ts Added OutOfProcessStringReaderUtf16 class using TextDecoder('utf-16le'); constructor accepts useUtf16StringTable flag
Boot.WebAssembly.Common.ts Registered Blazor._internal.renderBatchOOP handler
GlobalExports.ts Added renderBatchOOP to IBlazor._internal type
WebRendererId.cs / .ts Added WebAssemblyOOP = 4 enum value
ArrayBuilder.cs, ArrayBuilderMemoryStream.cs Added COMPONENTS_WEBASSEMBLY namespace conditional
WebAssembly.csproj Linked RenderBatchWriter.cs, ArrayBuilder.cs, ArrayBuilderMemoryStream.cs from Shared
WebAssemblyHost.cs Passes useOutOfProcessRendering flag based on __BLAZOR_WEBASSEMBLY_OOP_RENDERER env var
RazorComponentEndpointsStartup.cs Propagates OOP renderer env var to WASM
components-e2e-tests.yml Added CI step to run WebAssembly E2E tests with OOP renderer enabled

Opt-In Mechanism

The OOP renderer is opt-in via the __BLAZOR_WEBASSEMBLY_OOP_RENDERER environment variable set to "true". For E2E tests, EnableOOPRenderer config or ASPNETCORE_E2E_OOP_RENDERER env var propagates this.

Test Coverage

Six E2E tests validate the core rendering scenarios through the OOP path:

  • Component becomes interactive on WASM
  • Click event handling (counter increment)
  • Two-way text input binding
  • JS interop (IJSRuntime.InvokeAsync)
  • Conditional rendering (toggle visibility)
  • Dynamic list rendering (add items)

@pavelsavara pavelsavara added this to the .NET 11 Planning milestone Apr 23, 2026
@pavelsavara pavelsavara self-assigned this Apr 23, 2026
@pavelsavara pavelsavara added area-blazor Includes: Blazor, Razor Components arch-wasm labels Apr 23, 2026
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

Adds an opt-in “out-of-process” rendering path for Blazor WebAssembly that serializes RenderBatch data into a self-contained byte[] and passes it to JavaScript, avoiding shared-heap pointer access and the associated heap lock. It also extends the existing out-of-process batch parser to support a UTF-16LE string table encoding and adds E2E coverage plus CI execution for the new mode.

Changes:

  • Add a WebAssembly renderer mode that serializes render batches via RenderBatchWriter and dispatches them through a new renderBatchOOP JSImport.
  • Add UTF-16LE string-table serialization in .NET and decoding support in the JS out-of-process batch reader.
  • Add a test page + E2E tests and run an additional CI test pass with the OOP renderer enabled.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/Components/WebAssembly/WebAssembly/src/Rendering/WebAssemblyRenderer.cs Adds OOP rendering branch and new RenderBatchOOP JSImport to send serialized batches.
src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj Links shared rendering infrastructure (ArrayBuilder*, RenderBatchWriter) into the WASM assembly.
src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHost.cs Enables OOP rendering via __BLAZOR_WEBASSEMBLY_OOP_RENDERER env var.
src/Components/Web.JS/src/Rendering/WebRendererId.ts Adds WebAssemblyOOP enum value.
src/Components/Web.JS/src/Rendering/RenderBatch/OutOfProcessRenderBatch.ts Adds UTF-16LE string reader and plumbs a flag for string-table encoding selection.
src/Components/Web.JS/src/GlobalExports.ts Extends internal Blazor exports typing with renderBatchOOP.
src/Components/Web.JS/src/Boot.WebAssembly.Common.ts Registers Blazor._internal.renderBatchOOP handler to apply OOP batches without heap lock.
src/Components/test/testassets/Components.WasmMinimal/Pages/OOPRendererInteractivity.razor Adds a WASM interactivity test page used by E2E tests for the OOP renderer.
src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs Propagates the OOP renderer env var into the WASM environment for test runs.
src/Components/test/E2ETest/Tests/WebAssemblyOOPRendererTest.cs Adds E2E tests validating rendering + interactivity scenarios under the OOP renderer.
src/Components/test/E2ETest/Infrastructure/ServerFixtures/OOPRendererServerFixture.cs Adds a server fixture that turns on OOP rendering for test runs.
src/Components/Shared/src/WebRendererId.cs Adds WebAssemblyOOP enum value on the .NET side.
src/Components/Shared/src/RenderBatchWriter.cs Adds UTF-16LE string-table serialization option and constructor flag.
src/Components/Shared/src/ArrayBuilderMemoryStream.cs Adds WASM conditional namespace support for linked shared stream helper.
src/Components/Shared/src/ArrayBuilder.cs Adds WASM conditional namespace support for linked shared buffer helper.
.azure/pipelines/components-e2e-tests.yml Adds an additional CI run executing WebAssembly E2E tests with the OOP renderer enabled and publishes results.

Comment thread src/Components/Shared/src/RenderBatchWriter.cs Outdated
Comment thread src/Components/Shared/src/WebRendererId.cs
Comment thread src/Components/test/E2ETest/Tests/WebAssemblyOOPRendererTest.cs Outdated
pavelsavara and others added 3 commits April 24, 2026 14:04
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…PRendererInteractivity.razor

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

Labels

arch-wasm area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants