QwikDev / QwikDev/qwik

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

Open
#8,634 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug needs reproduction runtime SSR
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-webkit project) and Chromium

Symptom timing on cold load:

  1. First request: 15–17 s wall time, Importing a module script failed on 2–4 QRL chunks, page errors in console (functionality not necessarily broken, but tests checking errors.toEqual([]) fail).
  2. 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:

  1. Qwik app with multiple useVisibleTask$ components active on entry route.
  2. pnpm dev (Vite dev SSR, not built).
  3. Cold-load entry route in Playwright WebKit, capture console.error.
  4. Expect: empty error list. Observed: 2–4 Importing a module script failed errors.
  5. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.