Skip to content

fix(router): skip link data prefetch for loaders with unexpired in-memory data - #8870

Open
wmertens wants to merge 2 commits into
mainfrom
fix-link-prefetch-fresh-loaders
Open

fix(router): skip link data prefetch for loaders with unexpired in-memory data#8870
wmertens wants to merge 2 commits into
mainfrom
fix-link-prefetch-fresh-loaders

Conversation

@wmertens

Copy link
Copy Markdown
Member

What

Link data prefetch (intent/visible/commit) fetched q-loader-*.json for every loader on the target route. The only dedupe was the 5-second URL-keyed fetch cache, so hovering or scrolling past links re-ran route loaders on the server even when the loader's signal already holds fresh data client-side (within its expires window, default 2 min).

How

  • New internal core helper _hasValidSignalValue(signal) reads a computed signal's validity (has a value, not invalidated by dependency changes or expires) without triggering a computation.
  • The in-memory loader state (RouteStateContext) is threaded into the Link prefetch paths (Link handlers, the visible-link observer, and the post-nav observer refresh). prefetchRoute skips fetching any loader whose signal is still valid.
  • The nav-time prefetchRoute call intentionally does not skip: navigation invalidates those signals and refetches them, so the warm-up is still used.
  • The loader-data loop is extracted into prefetchLoaderData for direct unit testing (the isBrowser guard is compile-time in vitest).

Verification

  • prefetch-route.unit.ts (new): fresh signals are skipped, invalidated/missing loaders are fetched; all fetched when no state is given.
  • link-prefetch.unit.ts / link-component.unit.tsx: updated to assert the loader state is forwarded.
  • pnpm tsc.check, pnpm api.update, pnpm build.core, pnpm test.unit (206 files / 3200 tests) all pass.
  • Local browser e2e could not run due to a pre-existing Nix/npm Playwright version mismatch (nix browsers 1.57/rev 1200 vs npm 1.61/rev 1228); relying on CI for the e2e suite.

Security note: no new trust boundary — the change only skips client-initiated fetches based on client-local signal state; request construction is unchanged.

🤖 Generated with Claude Code

https://claude.ai/code/session_019cqZnyUrRaqBjTKaLQtUK3

@wmertens
wmertens requested a review from a team as a code owner July 21, 2026 23:44
Copilot AI review requested due to automatic review settings July 21, 2026 23:44
@maiieul maiieul moved this to Waiting For Review in Qwik Development Jul 21, 2026
@changeset-bot

changeset-bot Bot commented Jul 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 87e4382

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@qwik.dev/router Patch
@qwik.dev/core Patch
eslint-plugin-qwik Patch
@qwik.dev/react Patch
create-qwik Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 21, 2026

Copy link
Copy Markdown

Open in StackBlitz

@qwik.dev/core

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/core@8870

@qwik.dev/router

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/router@8870

eslint-plugin-qwik

npm i https://pkg.pr.new/QwikDev/qwik/eslint-plugin-qwik@8870

create-qwik

npm i https://pkg.pr.new/QwikDev/qwik/create-qwik@8870

@qwik.dev/optimizer

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/optimizer@8870

@qwik.dev/devtools

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/devtools@8870

commit: 87e4382

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Not ready to approve

The new _hasValidSignalValue() helper can misclassify pending/error async computed signals as “valid,” which can incorrectly skip needed prefetch fetches.

Pull request overview

This PR optimizes @qwik.dev/router link-triggered loader-data prefetching by avoiding q-loader-*.json fetches when loader data is already available client-side (within the loader signal’s validity window), reducing unnecessary server work during hover/visible/commit prefetch strategies.

Changes:

  • Added a core internal helper (_hasValidSignalValue) to detect whether a computed signal already holds a usable value without triggering computation.
  • Threaded router in-memory loader state through link prefetch entry points and updated prefetchRoute to skip fetching loader data when signals are still valid.
  • Added/updated unit tests and included a changeset for @qwik.dev/router and @qwik.dev/core.
File summaries
File Description
packages/qwik/src/core/reactive-primitives/utils.ts Adds _hasValidSignalValue() for checking computed signal cached-value validity without computing.
packages/qwik/src/core/qwik.core.api.md Updates extracted API docs to include the new internal helper.
packages/qwik/src/core/internal.ts Re-exports _hasValidSignalValue via core internal entrypoint.
packages/qwik-router/src/runtime/src/router-outlet-component.tsx Passes RouteStateContext into link prefetch initialization.
packages/qwik-router/src/runtime/src/qwik-router-component.tsx Threads loader state into link prefetch observer refresh calls.
packages/qwik-router/src/runtime/src/prefetch-route.unit.ts Adds unit coverage for loader-data prefetch skipping behavior.
packages/qwik-router/src/runtime/src/prefetch-route.ts Adds loader-state-aware skipping and extracts prefetchLoaderData helper.
packages/qwik-router/src/runtime/src/link-prefetch.unit.ts Updates observer tests to assert loader state forwarding.
packages/qwik-router/src/runtime/src/link-prefetch.ts Threads optional loader state through observer and prefetch calls.
packages/qwik-router/src/runtime/src/link-component.unit.tsx Updates Link tests to assert loader state forwarding to prefetchRoute.
packages/qwik-router/src/runtime/src/link-component.tsx Reads RouteStateContext and forwards loader state into prefetchRoute calls.
.changeset/olive-pandas-repeat.md Adds patch changeset for router + core behavior change.

Review details

  • Files reviewed: 12/12 changed files
  • Comments generated: 1
  • Review effort level: Low

Note

Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/qwik/src/core/reactive-primitives/utils.ts
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor
built with Refined Cloudflare Pages Action

⚡ Cloudflare Pages Deployment

Name Status Preview Last Commit
qwik-docs ✅ Ready (View Log) Visit Preview 87e4382

@wmertens
wmertens force-pushed the fix-link-prefetch-fresh-loaders branch 3 times, most recently from c391677 to 580dbae Compare July 27, 2026 06:23
wmertens added 2 commits July 27, 2026 08:48
data prefetching was always fetching loader data even when still-valid data was already on the client
@wmertens
wmertens force-pushed the fix-link-prefetch-fresh-loaders branch from 580dbae to 87e4382 Compare July 27, 2026 06:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Waiting For Review

Development

Successfully merging this pull request may close these issues.

3 participants