QRL chunks fail to load on cold Vite dev SSR requests (beta.35 + Vite 8) — `TypeError: Importing a module script failed` + 504 Outdated Optimize Dep
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 22.1k
- Forks
- 1.4k
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 52
Description
Which area(s) are affected?
Qwik Runtime, Rollup / Vite plugin
Describe the bug
In Vite dev SSR (pnpm dev), the first request to a route that uses useVisibleTask$ produces TypeError: Importing a module script failed on multiple QRL chunks. Subsequent requests succeed.
qrl WebVitals_component_useVisibleTask_yn4FTDO7PRs failed to load TypeError: Importing a module script failed.
qrl Link_component_useVisibleTask_xKeuRmnoNSA failed to load TypeError: Importing a module script failed.
qrl PWAProvider_component_useVisibleTask_PiqqFnaN19Y failed to load TypeError: Importing a module script failed.
Often accompanied by a 504 (Outdated Optimize Dep) from Vite for one of the requested chunks:
Failed to load resource: the server responded with a status of 504 (Outdated Optimize Dep)
The pattern looks like Vite's dep-optimization invalidating chunk URLs mid-request: the page renders, qwikloader starts importing QRL chunks, Vite re-optimizes and changes the chunk hashes, the in-flight imports point at stale URLs and 504.
History across versions:
- beta.32: Present but invisible — qwikloader handled the failure gracefully.
- beta.34: Became deterministic, broke pages outright. We held at beta.32 for two release cycles.
- beta.35: PR #8606 (skip preloader in dev) reduced it to a one-retry flake under Playwright. Shipped, but still visible on cold loads.
Production builds are unaffected — only Vite dev SSR.
Reproduction
I don't have a self-contained min-repro yet. The flake appears tied to overall project complexity / dependency-graph size and may not surface in a trimmed-down project. Filing this with embedded evidence and willing to construct a min-repro if a maintainer can suggest what scale of components / cold-load conditions to target.
What our setup looks like (private codebase, so I can't link it):
- ~6 components using
useVisibleTask$near the entry route (/auth/sign-in) - Cloudflare-Workers SSR adapter, Vite dev for local
- Playwright cold-loads in WebKit (
mobile-webkitproject) and Chromium
Symptom timing on cold load:
- First request: 15–17 s wall time,
Importing a module script failedon 2–4 QRL chunks, page errors in console (functionality not necessarily broken, but tests checkingerrors.toEqual([])fail). - Retry: 1.5–3.5 s, succeeds cleanly.
If we re-enable Qwik's built-in qwikLoader: "module" (default), qwikloader itself joins the failed-chunk set and interactivity breaks deterministically on Chromium (market-explorer: navigate to detail, portfolio-grid: search filters failed even after 2 retries).
Steps to reproduce
Approximate — minimum complexity to surface this isn't established yet:
- Qwik app with multiple
useVisibleTask$components active on entry route. pnpm dev(Vite dev SSR, not built).- Cold-load entry route in Playwright WebKit, capture
console.error. - Expect: empty error list. Observed: 2–4
Importing a module script failederrors. - Reload: clean.
System Info
System:
OS: macOS 26.5 (Apple Silicon, Apple M5 Pro)
Shell: zsh 5.9
Binaries:
Node: 22.22.2
pnpm: 10.33.2
Browsers (also confirmed in Playwright Linux Ubuntu CI):
Safari: 26.5
Chrome: 148.0.7778.97
npmPackages:
@qwik.dev/core: 2.0.0-beta.35
@qwik.dev/router: 2.0.0-beta.35
@playwright/test: 1.60.0
vite: 8.0.13
CI environment where the same pattern reproduces: Ubuntu 24.04, Node 22, fresh pnpm dev, Playwright mobile-webkit against http://localhost:3000.
Additional Information
Workaround that's load-bearing for us today — removing it deterministically breaks interactivity:
// entry.ssr.tsx
return renderToStream(<Root />, {
...opts,
qwikLoader: "never", // skip Qwik's built-in qwikloader emission
manifest,
});
// root.tsx
<head>
{/* ... */}
<script src="/qwikloader.js" async /> {/* non-module static asset */}
</head>
/qwikloader.js is a hand-copy of node_modules/@qwik.dev/core/dist/qwikloader.js wrapped in an IIFE, served as a non-module script. This bypasses Vite's dev module resolver entirely.
Hypothesis: Vite's dep-optimization cache for SSR is invalidating chunk URLs mid-import during cold requests, and Qwik's QRL loader doesn't tolerate the 504 Outdated Optimize Dep response. The non-module static loader works because Vite doesn't intercept non-module <script> tags.
Happy to build a minimal repro, capture HAR + Vite dep-cache state during a cold request, or run targeted experiments (e.g., disable optimizeDeps, vary number of useVisibleTask$ components) if useful.
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 entry.ssr.tsx and root.tsx, then reproduce with pnpm dev and a cold Playwright load of a route using multiple useVisibleTask$ components. Compare the built-in qwikLoader behavior with the documented static-loader workaround and inspect PR #8606. Done means the first request completes without QRL import errors or 504 Outdated Optimize Dep responses, while production remains unaffected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- playwright, typescript, vite
- Domain
- build-system, frontend, testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 38/100