Fix Safari: strip dead worker-entry export that breaks shell boot#838
Merged
brandonpayton merged 1 commit intoJul 3, 2026
Merged
Conversation
The browser demos never finish booting in Safari/WebKit — the shell
freezes at "instantiating kernel..." with no error. Chromium and Firefox
are fine, and it only reproduces in the production build, so it is invisible
on the Vite dev server.
Root cause: rolldown (Vite 8's bundler) synthesizes a dead `export { … }` on
the kernel/process worker entry chunks. The source has no such export and
nothing imports it. But its presence makes WebKit evaluate the `type:"module"`
worker TWICE: the second (uninitialized) evaluation reinstalls `self.onmessage`
bound to a fresh module state whose `initReady` is false, shadowing the first
evaluation's handler. The kernel worker posts `ready`, but the main thread's
follow-up `register_lazy_files`/`register_lazy_archives` requests are then
handled by the uninitialized handler, which parks them in its pending queue and
never acks — so `kernel.init()` never resolves and the machine never boots.
Fix: a worker-build Vite plugin (`dropWorkerEntryExports`) strips the dead
trailing `export { … }` from worker entry chunks at `renderChunk`, making the
worker a single-evaluation module on every engine. The "proper" lever,
`preserveEntrySignatures: false`, has no effect here — rolldown-vite does not
thread it into the worker build (see the inline note to revisit).
Verified on real Safari 26.5 (via safaridriver) and Playwright WebKit against a
production build served like GitHub Pages (service worker injects COOP/COEP):
baseline hangs, fixed build boots and runs a shell command. No Chromium
regression.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
prepare-merge: runtime/materialization tests passed against the synthetic PR merge; package staging and durable package publishing were skipped. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The deployed browser demos (https://automattic.github.io/kandelo/) never finish booting in Safari/WebKit — the shell freezes at
instantiating kernel...with no console error. Chromium and Firefox are unaffected. It only reproduces in the production build, so it's invisible on the Vite dev server (which is why it couldn't be reproduced locally at first).Root cause
Rolldown (Vite 8's bundler) synthesizes a dead
export { … }on the kernel/process worker entry chunks. The source has no such export and nothing imports it — but its presence makes WebKit evaluate thetype:"module"worker twice:init, setsinitReady = true, postsready.self.onmessage, bound to a fresh module state whoseinitReadyis false — shadowing feat: centralized multi-process kernel #1's handler.kernel.init()then sendsregister_lazy_files/register_lazy_archivesand waits for an ack. Those are now handled by the uninitialized handler, which parks them in its!initReadypending queue and never replies.kernel.init()never resolves → the machine never boots.Fix
A worker-build Vite plugin (
dropWorkerEntryExports) strips the dead trailingexport { … }from worker entry chunks atrenderChunk, so the worker is a single-evaluation module on every engine.The "proper" lever —
preserveEntrySignatures: false— has no effect here: rolldown-vite (Vite 8 / rolldown 1.0.3) doesn't thread that option into the worker build (byte-identical output). There's an inline, dated note to revisit and drop this plugin once it does.Verification
Reproduced and verified on real Safari 26.5 (via
safaridriver) and Playwright WebKit, against a production build served exactly like GitHub Pages (service worker injects COOP/COEP, no direct headers):echo)Confirmed the rebuilt worker chunks (kernel worker and nested process worker) no longer contain any
export, and the command-run test proves the nested process worker still spawns.Scope
One file:
apps/browser-demos/vite.config.ts. No runtime/kernel/ABI changes.🤖 Generated with Claude Code