fix(router): skip link data prefetch for loaders with unexpired in-memory data - #8870
fix(router): skip link data prefetch for loaders with unexpired in-memory data#8870wmertens wants to merge 2 commits into
Conversation
🦋 Changeset detectedLatest commit: 87e4382 The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
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 |
@qwik.dev/core
@qwik.dev/router
eslint-plugin-qwik
create-qwik
@qwik.dev/optimizer
@qwik.dev/devtools
commit: |
There was a problem hiding this comment.
⚠️ 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
prefetchRouteto skip fetching loader data when signals are still valid. - Added/updated unit tests and included a changeset for
@qwik.dev/routerand@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.
built with Refined Cloudflare Pages Action⚡ Cloudflare Pages Deployment
|
c391677 to
580dbae
Compare
data prefetching was always fetching loader data even when still-valid data was already on the client
580dbae to
87e4382
Compare
What
Linkdata prefetch (intent/visible/commit) fetchedq-loader-*.jsonfor 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 itsexpireswindow, default 2 min).How
_hasValidSignalValue(signal)reads a computed signal's validity (has a value, not invalidated by dependency changes orexpires) without triggering a computation.RouteStateContext) is threaded into the Link prefetch paths (Linkhandlers, the visible-link observer, and the post-nav observer refresh).prefetchRouteskips fetching any loader whose signal is still valid.prefetchRoutecall intentionally does not skip: navigation invalidates those signals and refetches them, so the warm-up is still used.prefetchLoaderDatafor direct unit testing (theisBrowserguard 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.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