Skip to content

Make web editor cross-origin isolation reload reliable - #195

Open
Auburn wants to merge 1 commit into
masterfrom
fix/web-editor-isolation-reload
Open

Auburn wants to merge 1 commit into
masterfrom
fix/web-editor-isolation-reload

Conversation

@Auburn

@Auburn Auburn commented Oct 10, 2026

Copy link
Copy Markdown
Owner

The web editor's bootstrap (emscripten_enable_shared_array_buffer.js) registers a service worker that adds COOP/COEP headers, then reloads so the page is served cross-origin isolated (needed for SharedArrayBuffer/WASM threads). The page-side reload logic had several startup races and failure modes that leave the editor on a black canvas or reload it endlessly:

  • It reloaded on updatefound, while the worker is only just installing, so the reloaded page often wasn't controlled yet and needed a second reload. If the register() result arrived after the worker had already activated and claimed the page, it didn't reload at all.
  • A page taken over by clients.claim() (F5 or a second tab during the first install) counted as controlled and was never reloaded, even though it hadn't been served with COOP/COEP.
  • There was no loop guard. When navigations bypass the worker (e.g. DevTools "Bypass for network"), it reloaded forever.
  • It threw an unhandled TypeError on insecure origins, where navigator.serviceWorker is undefined.

Changes (page side only; the worker is unchanged)

  • Wait until this script's own worker is active, then reload.
  • Reload at most once per attempt, marked with #coi-reloaded in the URL (stripped on the next load). If the page is still not isolated after that reload, log a warning that isolation is being blocked instead of reloading again. The marker lives in the URL because Chrome switches browsing context group when COOP starts or stops applying. Across that switch, a sessionStorage flag can come back stale after a hard reload (the editor then gives up), and history.state is dropped.
  • Warn and stop when service workers are unavailable.

Testing

Ran a local harness: the real emscripten_shell.html with a stub NodeEditor module, in fresh headless Chrome 155 and Firefox 157 profiles (3–10 runs per case).

Scenario master this PR
First visit 1 reload; 2 in ~30% of Chrome runs 1 reload
register() result delivered 300 ms late stays non-isolated 1 reload, isolated
Page claimed before the bootstrap runs (F5 or second tab during install) stays non-isolated 1 reload, isolated
Navigations bypass the worker (Chrome DevTools) endless reloads 1 reload, then warning
Isolation impossible (iframe in a non-isolated page; Chrome Permissions-Policy) 1 reload, no message 1 reload, warning
Scope controlled by another worker without COOP/COEP Chrome stays non-isolated, Firefox recovers recovers in both
Insecure origin unhandled TypeError warning
Normal reload / hard reload (hard: Chrome only) OK OK

Not covered: Safari, and the real WASM build (JS-only change, no native code touched).

Possibly related to the black screen reported in #185, but that report's cause isn't confirmed, so this doesn't claim to fix it.

- Reload once this script's own worker is active, not on updatefound or a stale active/controller check
- Reload at most once per attempt (URL fragment marker); warn instead of looping when isolation is blocked
- Warn instead of throwing when service workers are unavailable

This branch has not been deployed

No deployments
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