Skip to content

Windows (New Architecture): production feedback on the WebView2 implementation + offer of hardening PRs #3980

Open

Description

@FaithfulAudio

We ship a production react-native-windows 0.83.2 New-Architecture app (Win32 composition, WinAppSDK 1.8, ARM64) with an independently-built WebView2 Fabric component that converged on exactly the architecture #3973 landed: WinUI 3 WebView2 → Microsoft.UI.Xaml.XamlIsland → ContentIsland → RNW ContentIslandComponentView.Connect(). It renders real web content in the field today, so first: the XamlIsland/ContentIsland approach in #3973 is solid — we can confirm first pixel, load events, postMessage round-trips, and teardown behavior (including the "orphaned island breaks window-wide input" trap your comment in RCTWebView2ComponentView.cpp also documents) on independent code.

Reading windows/ReactNativeWebView/RCTWebView2ComponentView.cpp against our production component, we found a handful of places where our implementation had to harden the same code paths, and we'd like to upstream them as a small PR series.

  1. No onError when the WebView2 Runtime is missing. EnsureCoreWebView2Async() is called without an environment and without failure handling (InitializeContentIsland). On machines without the Evergreen Runtime (stripped/managed images, Server SKUs) the view stays blank with no JS-visible signal. We create the environment explicitly (CoreWebView2Environment::CreateWithOptionsAsync) with a writable, packaged-safe user-data folder, catch failures, and emit onLoadingError with the HRESULT — both when environment creation itself throws (Runtime entirely missing) and via CoreWebView2InitializedEventArgs.Exception() (failure after an environment was created).
  2. Failed navigations emit onLoadingFinish. OnNavigationCompleted doesn't consult args.IsSuccess()/WebErrorStatus(), so DNS failures, TLS errors, and offline states look like successful loads to JS. We branch and emit onLoadingError with the CoreWebView2WebErrorStatus instead. While in there: title (DocumentTitle()) already exists as a field on every nav-event struct in the codegen (RCTWebView2.g.h) but is never populated on Windows — we fill it in on onLoadingStart/onLoadingFinish/onLoadingError/onSourceChanged.
  3. Bridge timing: window.ReactNativeWebView is injected post-load in NavigationCompleted; page scripts that run during load (a synchronous inline <script> in <head>, for example) can't see it, and the WebMessageReceived handler is re-registered on every NavigationStarting. Registering the bridge once via AddScriptToExecuteOnDocumentCreatedAsync when CoreWebView2 becomes available makes it exist before any page script runs on every subsequent navigation — and the same mechanism wires up injectedJavaScriptBeforeContentLoaded, which already exists in the codegen'd prop spec but isn't read on Windows yet.
  4. javaScriptEnabled set before core-init is lost (applied in UpdateProps only when CoreWebView2() already exists; OnCoreWebView2Initialized re-applies only userAgent and pending HTML, never javaScriptEnabled).
  5. UpdateProps re-navigates on unrelated prop changes. It receives the full current prop set on every call (not a diff), and unconditionally re-sets m_webView.Source(uri) / calls NavigateToString(html) whenever a source is present — so toggling an unrelated prop like javaScriptEnabled can re-navigate/reload the page as a side effect. We diff against oldProps (already a parameter, currently unused) before navigating.

We've opened a 4-PR series against master, each independently revertible, in roughly ascending order of size:

  • WV-1 — item 1 (environment + init-error onError)
  • WV-2 — item 2 (IsSuccess() honored + title in nav events)
  • WV-3 — item 3 (document-start bridge + injectedJavaScriptBeforeContentLoaded)
  • WV-4 — item 4 + 5 (javaScriptEnabled lifecycle + source-diffing)

All four are marked draft: we have not compiled them against this repo (no Windows build was run this pass — the changes are hand-verified by side-by-side reading against your RCTWebView2ComponentView.cpp, not by bun run windows), and each PR description says so explicitly. Every fix mirrors a code path already running in production in a parallel Windows new-arch WebView2 Fabric component — see FacilitronWorks/react-native-webview-windows — but that component uses renamed symbols and isn't a drop-in diff, so the PRs are hand-ported to your codegen/class shape, not copy-pasted.

Two questions before we go further:

Context for anyone landing here from search: for apps pinned to react-native-webview versions before Windows New Architecture support landed, we also maintain a small companion package with these fixes (FacilitronWorks/react-native-webview-windows) — the plan is to upstream everything above and retire it.

Activity

  1. FaithfulAudio commented on Jul 11, 2026

    @FaithfulAudio
    Author

    Opened the series:

    All four are draft — none compiled against this repo yet, each PR body says so explicitly. Each is based directly on master and independently revertible; happy to rebase/squash however you'd prefer if more than one lands.

  2. flawrist commented on Jul 11, 2026

    @flawrist

    I don't know where to post this, since modern developers have changed the web beyond recognition, so I'm hoping someone can point me in the right direction.

    This week (July 2026), I can no longer leave comments on Github which uses React. Some React module requires .toSorted method. It is not supported by Chrome/Edge 109, the browser I use on Windows 7 x64. The solution is extremely simple — just add a polyfill to your codebase like this:

        if (!Array.prototype.toSorted) {
            Array.prototype.toSorted = function(c) {
                return this.slice().sort(c);
            };
        }
    

    Guys, with your endless quest to optimize and make everything glow, you're ruining the way to communicate with others that has worked for decades.

  3. Titozzz commented on Jul 14, 2026

    @Titozzz
    Collaborator

    Since I'm not using webview on Windows myselfn let me ping folks at microsoft @Nitin-100 @anupriya13

  4. FaithfulAudio commented on Jul 15, 2026

    @FaithfulAudio
    Author

    Thanks @Titozzz, appreciate the ping. Quick orientation: the four PRs (#3981 environment + init-error onError, #3982 IsSuccess()/title in nav events, #3983 document-start bridge + injectedJavaScriptBeforeContentLoaded, #3984 javaScriptEnabled lifecycle) are each based on master, independently revertible, and touch only the Windows/WebView2 path — nothing in shared, iOS, or Android. They're still draft because I haven't compiled them against this repo's build yet; the fixes were validated in our production RNW 0.83 new-arch app. Happy to walk through any root cause or rebase if more than one lands.

  5. tido64 commented on Aug 4, 2026

    @tido64
    Contributor

    @acoates-ms, @vmoroz: Is this something you can take a look at?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions