qwikloader: WebKit may defer the async module loader while a stream is held, losing pre-resume clicks
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 22.1k
- Forks
- 1.4k
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 52
Description
What is it?
- Bug
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).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the default Module emission and the error-handling.e2e.ts midstream queue-and-replay test; reproduce on Playwright WebKit while the gated Suspense child holds the stream, and compare Chromium. Done when WebKit evaluates the loader during the hold and clicks are queued and replayed, with the nonce-aware loading path verified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- playwright, typescript
- Domain
- frontend, testing-qa, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100