Skip to content

fix(desktop): gate the Browser pane's media pause on dom-ready#239

Open
AprilNEA wants to merge 1 commit into
masterfrom
xuan/code-380
Open

fix(desktop): gate the Browser pane's media pause on dom-ready#239
AprilNEA wants to merge 1 commit into
masterfrom
xuan/code-380

Conversation

@AprilNEA

Copy link
Copy Markdown
Member

Fixes CODE-380. Shipped in v0.6.0 and v0.6.1 — the desktop renderer boots to a blank window with no error surface for anyone who has opened a page in the Browser pane.

Root cause

BrowserWebviewPane's hidden-media pause calls WebviewTag.executeJavaScript on a guest that is not attached yet. That method throws synchronously — it does not return a rejected promise — so the .catch(noop) never sees it, the error escapes the effect, and React tears down the entire tree.

Introduced by #224 (d078fd49, sub-commit fix(desktop): pause Browser pane media when the panel is hidden), not by the resident-webview work that preceded it.

Why it hits real users

The crash needs webview !== null && !visible, and both hold on an ordinary launch:

  1. <webview> mounts whenever rightPanel.browser.url !== null, and that URL is persisted — durableBrowserUrl (store/model.ts:317) drops only blob: URLs.
  2. visible = rightPanel.open && activeSection === 'browser' is false whenever Browser is not the active section at boot.

The ref callback sets the element long before dom-ready, so the effect fires at mount. Mount-while-hidden is the resident webview's normal path, not an edge case.

Fix

Track a guestReady flag from a dom-ready listener registered alongside the existing nav listeners, and gate the pause effect on it. The flag resets in the ref callback so a replacement element starts not-ready instead of inheriting the previous guest's state. Nothing is swallowed: the .catch(noop) remains only for the genuine post-ready async failure.

Verification

A probe forcing the exact production trigger (persisted Browser URL, Browser section not active), same build steps on each side:

#root children <webview> pageerror
master 0 0 The WebView must be attached to the DOM…
this branch 1 1 none

pnpm check:ci and pnpm test (222 files / 1732 tests) pass.

@linear-code

linear-code Bot commented Jul 21, 2026

Copy link
Copy Markdown

CODE-380

@greptile-apps

greptile-apps Bot commented Jul 21, 2026

Copy link
Copy Markdown

Greptile Summary

This PR prevents the hidden Browser pane from pausing media before its guest is ready. The main changes are:

  • Tracks the guest that emitted dom-ready by element identity.
  • Registers readiness handling with the existing webview listeners.
  • Gates hidden-media JavaScript execution on the current guest's readiness.

Confidence Score: 5/5

This looks safe to merge.

The identity-based state preserves readiness when React reapplies the callback ref to the same element. A replacement webview remains gated until its own dom-ready event.

No blocking issues were found in the updated readiness flow.

T-Rex T-Rex Logs

What T-Rex did

  • Generated the requested real-app probe from the Browser WebView Lifecycle Probe source artifact.
  • Verified the probe build; the retry completed successfully as shown in the Browser WebView Lifecycle Build Log.
  • Inspected the latest runtime log (Runtime Log) which shows a mounted real renderer with PAGE_ERRORS_AFTER_HIDDEN_STARTUP [] but webviews: 0, marking this as blocker/debug evidence rather than success.
  • Adjusted the probe to seed localStorage in the current renderer before reload, but maximum steps prevented rerun.
  • Planned to rerun the corrected probe under Xvfb to verify hidden-startup root/webview counts and zero page errors, preserve its screenshot/video, and optionally rebuild the parent revision for the before-capture run.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
apps/desktop/src/renderer/src/shell/browser/browser-webview-pane.tsx Tracks readiness by webview identity and delays hidden-media JavaScript execution until the current guest emits dom-ready.

Reviews (2): Last reviewed commit: "fix(desktop): gate the Browser pane's me..." | Re-trigger Greptile

Comment thread apps/desktop/src/renderer/src/shell/browser/browser-webview-pane.tsx Outdated
executeJavaScript throws synchronously on an unattached guest, so the .catch
never ran and the escaping error unmounted the whole renderer.
@AprilNEA

Copy link
Copy Markdown
Member Author

The dom-ready update triggers a render, and the recreated callback ref resets readiness for the same webview.

Measured this rather than reasoning about it — the concern does not reproduce here, because React Compiler (enabled for this renderer via reactCompilerPreset() in vite.renderer.config.ts) memoizes captureWebview, so its identity is stable and React never detaches/reattaches the ref on re-render.

Instrumented the ref callback and the pause effect, then ran a real-Electron probe that forces the production trigger (persisted Browser URL, Browser section not active):

refCalls:   ["element"]                                        // one attach, no null detach
pauseEffect: ["webview=false visible=false ready=false",       // no element yet -> return
              "webview=true  visible=false ready=false",       // the old crash point -> return
              "webview=true  visible=false ready=true"]        // runs
pauseRan:   1

So readiness reaches true, stays true, and the hidden-media pause still fires exactly once.

That said, the coupling you pointed at is worth removing — correctness here should not depend on whether the compiler memoizes. Pushed a revision that holds readiness by element identity instead of a boolean plus a reset:

const [readyGuest, setReadyGuest] = useState<WebviewTag | null>(null);
const guestReady = webview !== null && readyGuest === webview;

A replacement element is then simply not the ready one, so the setGuestReady(false) in the ref callback disappears entirely — one less state write and no reset invariant to keep in sync. Re-ran the same instrumented probe after the change: identical trace, pauseRan: 1, no page errors.

Also rebased onto current master. pnpm check:ci and pnpm test (1732 tests) pass.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant