What is it?
Description
With the default loader emission (QwikLoaderInclude.Module: <link rel="modulepreload"> + <script async type="module" src=".../qwikloader.js">), WebKit sometimes never evaluates the loader while the HTML stream is held open (e.g. an in-order region awaiting a deferred child). Until evaluation, no qwikloader listeners exist, so user clicks during the hold are lost instead of queued and replayed at resume. Chromium evaluates the async module as soon as it is fetched and queues the clicks correctly.
Observed on the error-handling e2e app's midstream route (in-order streaming, stream held by a gated Suspense child): window._qwikEv.roots (set only by loader evaluation) never appears on WebKit within 90s, both on CI (macos-latest) and locally (macOS 26.5 / Playwright WebKit 26.5), while the same page's inline scripts (qErr swap) run fine. The behavior is bimodal — some runs evaluate promptly — so it looks like WebKit only drains ready async scripts on parser activity, and a fully quiet hold starves them. Streaming extra padding bytes mid-hold did not reliably help.
Production impact: any Qwik page whose stream stalls (slow loader, held Suspense region) has a WebKit window where clicks are dropped instead of queued.
Possible direction: emit the Module include as a tiny inline classic script that dynamic-imports the loader (<script>import("…/qwikloader.js")</script>, nonce-aware). Dynamic import evaluation rides the microtask queue, not the parser's async-script runner, so it is immune to the starvation. Needs verification on WebKit.
The error-handling.e2e.ts mid-stream queue-and-replay test parks WebKit on this issue (the invariant stays pinned on Chromium, Linux + Windows).
What is it?
Description
With the default loader emission (
QwikLoaderInclude.Module:<link rel="modulepreload">+<script async type="module" src=".../qwikloader.js">), WebKit sometimes never evaluates the loader while the HTML stream is held open (e.g. an in-order region awaiting a deferred child). Until evaluation, no qwikloader listeners exist, so user clicks during the hold are lost instead of queued and replayed at resume. Chromium evaluates the async module as soon as it is fetched and queues the clicks correctly.Observed on the
error-handlinge2e app'smidstreamroute (in-order streaming, stream held by a gated Suspense child):window._qwikEv.roots(set only by loader evaluation) never appears on WebKit within 90s, both on CI (macos-latest) and locally (macOS 26.5 / Playwright WebKit 26.5), while the same page's inline scripts (qErrswap) run fine. The behavior is bimodal — some runs evaluate promptly — so it looks like WebKit only drains ready async scripts on parser activity, and a fully quiet hold starves them. Streaming extra padding bytes mid-hold did not reliably help.Production impact: any Qwik page whose stream stalls (slow loader, held Suspense region) has a WebKit window where clicks are dropped instead of queued.
Possible direction: emit the Module include as a tiny inline classic script that dynamic-imports the loader (
<script>import("…/qwikloader.js")</script>, nonce-aware). Dynamic import evaluation rides the microtask queue, not the parser's async-script runner, so it is immune to the starvation. Needs verification on WebKit.The
error-handling.e2e.tsmid-stream queue-and-replay test parks WebKit on this issue (the invariant stays pinned on Chromium, Linux + Windows).