Skip to content

feat: add page data preloading for navigation#83

Merged
rsbh merged 9 commits into
mainfrom
worktree-proud-tickling-lampson
May 18, 2026
Merged

feat: add page data preloading for navigation#83
rsbh merged 9 commits into
mainfrom
worktree-proud-tickling-lampson

Conversation

@rsbh
Copy link
Copy Markdown
Member

@rsbh rsbh commented May 18, 2026

Summary

  • Add @tanstack/react-query for cache-aware data fetching
  • Preload /api/page data on hover, focus, and viewport intersection via global event delegation
  • PageProvider.fetchPageData now uses queryClient.fetchQuery — prefetched data served instantly
  • Skip prefetch for /apis/* routes (use different endpoint)

Test plan

  • Dev server starts without errors
  • Prefetch requests visible in Network tab on hover/scroll
  • Navigation to prefetched pages loads instantly (no loading spinner)
  • API pages not prefetched unnecessarily
  • Verify no regressions in SSR hydration
  • Test with versioned docs example

🤖 Generated with Claude Code

rsbh and others added 5 commits May 18, 2026 12:18
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Singleton QueryClient with prefetchPageData for cache-aware preloading
of /api/page responses.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fetchPageData now goes through react-query cache — prefetched data
is served instantly without duplicate network requests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Global event delegation prefetches page data on mouseover/focusin.
IntersectionObserver + MutationObserver handle viewport-visible and
dynamically added links. Wired up in entry-client.tsx.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
API pages use /api/specs not /api/page, so prefetch requests
for /apis/* paths were returning errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chronicle Ready Ready Preview, Comment May 18, 2026 8:11am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

Review Change Stack

Warning

Rate limit exceeded

@rsbh has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 55 minutes and 52 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a7223538-4387-43cd-81e2-b89501f6c8a8

📥 Commits

Reviewing files that changed from the base of the PR and between 48b8b0f and dc97ecc.

📒 Files selected for processing (4)
  • packages/chronicle/package.json
  • packages/chronicle/src/components/ui/PrefetchProvider.tsx
  • packages/chronicle/src/pages/DocsLayout.tsx
  • packages/chronicle/src/server/entry-client.tsx
📝 Walkthrough

Walkthrough

This PR adds TanStack React Query to Chronicle to enable intelligent page-data prefetching based on user interactions (hover, focus, viewport intersection) and consolidates caching logic. A shared QueryClient is created with custom defaults, a PrefetchProvider component registers prefetch triggers, the existing page-data fetch is updated to use React Query, and the app is wrapped with QueryClientProvider at the root.

Changes

React Query Prefetch Implementation

Layer / File(s) Summary
React Query Setup and Prefetch Infrastructure
packages/chronicle/package.json, packages/chronicle/src/lib/preload.ts
Adds @tanstack/react-query dependency and creates a shared QueryClient with infinite staleTime and disabled focus-based refetch. Exports pageDataQueryKey to derive stable query keys from pathnames, prefetchPageData to prefetch page data while skipping /apis routes, and internal fetchPageDataByPathname to fetch and throw on non-OK responses.
PrefetchProvider Component
packages/chronicle/src/components/PrefetchProvider.tsx
Implements a wrapper component that registers event listeners for mouseover and focusin on internal anchor elements, plus an IntersectionObserver (with rootMargin: '200px') and a MutationObserver to discover and prefetch newly inserted links. Cleans up all listeners and observers on unmount.
Page Data Fetching Integration
packages/chronicle/src/lib/page-context.tsx
Refactors fetchPageData to call queryClient.fetchQuery with a query key derived from the slug, delegating caching and deduplication to React Query while preserving HTTP error handling.
Root Provider Setup
packages/chronicle/src/server/entry-client.tsx
Imports QueryClientProvider and the shared queryClient, then wraps the existing provider tree (PageProvider and downstream providers) with QueryClientProvider to enable React Query functionality across the app.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • raystack/chronicle#50: Both PRs touch packages/chronicle/src/lib/page-context.tsx in the page-data fetching pipeline—main PR switches fetchPageData to React Query (queryClient.fetchQuery) while the retrieved PR adds PageProvider's isLoading/loading flow for DocsPage—so they are directly related at the same fetching logic.
  • raystack/chronicle#35: Both PRs modify packages/chronicle/src/lib/page-context.tsx's page-data fetching logic (main PR refactors fetchPageData to use TanStack queryClient.fetchQuery, while PR #35 changes the same fetch flow to surface non-OK responses via errorStatus/404 handling), so their changes are directly code-overlapping.

Suggested reviewers

  • rohanchkrabrty
  • rohilsurana
  • paanSinghCoder
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main change: adding page data preloading for navigation, which aligns with the core feature across all modified files.
Description check ✅ Passed The description is clearly related to the changeset, detailing the addition of react-query, preloading mechanisms, and specific test coverage.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-proud-tickling-lampson

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/chronicle/src/lib/page-context.tsx (1)

16-16: ⚡ Quick win

Reuse the shared page-data query-key helper to avoid key drift.

fetchPageData rebuilds the key inline while prefetching uses pageDataQueryKey(...). Keeping a single key derivation path avoids silent prefetch cache misses later.

Suggested refactor
-import { queryClient } from '`@/lib/preload`';
+import { pageDataQueryKey, queryClient } from '`@/lib/preload`';
@@
-    return queryClient.fetchQuery({
-      queryKey: ['pageData', key],
+    const pathname = `/${slug.join('/')}`;
+    return queryClient.fetchQuery({
+      queryKey: pageDataQueryKey(pathname),
       queryFn: async () => {

Also applies to: 118-122

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chronicle/src/lib/page-context.tsx` at line 16, fetchPageData is
constructing the page-data query key inline whereas prefetching uses the shared
pageDataQueryKey(...) helper, causing possible cache misses; update
fetchPageData to import and call pageDataQueryKey(...) instead of rebuilding the
key, and use that same key when calling
queryClient.fetchQuery/fetchInfiniteQuery so both producers/consumers use the
identical key derivation (apply the same change for the other occurrence around
lines 118-122). Ensure you replace any inline array/object key construction in
fetchPageData with a single call to pageDataQueryKey(...) and pass that result
to queryClient operations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/chronicle/src/components/PrefetchProvider.tsx`:
- Around line 4-5: The prefetch logic is using raw getAttribute('href') which
can yield relative URLs or include query/hash and cause wrong slugs; update
isInternalLink and the anchor handling in PrefetchProvider to resolve each href
against location.href via new URL(href, location.href), ensure the URL.origin
=== location.origin (to keep same-origin), then use url.pathname (normalized,
without query/hash) as the prefetch key/route to check/prefetch; replace any
direct uses of the raw href (from getAttribute('href')) with this normalized
pathname in functions such as isInternalLink and the anchor prefetch handlers so
caching and /api/page requests target the canonical path.

---

Nitpick comments:
In `@packages/chronicle/src/lib/page-context.tsx`:
- Line 16: fetchPageData is constructing the page-data query key inline whereas
prefetching uses the shared pageDataQueryKey(...) helper, causing possible cache
misses; update fetchPageData to import and call pageDataQueryKey(...) instead of
rebuilding the key, and use that same key when calling
queryClient.fetchQuery/fetchInfiniteQuery so both producers/consumers use the
identical key derivation (apply the same change for the other occurrence around
lines 118-122). Ensure you replace any inline array/object key construction in
fetchPageData with a single call to pageDataQueryKey(...) and pass that result
to queryClient operations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5459522d-065b-4cb2-aa08-d106a90795fa

📥 Commits

Reviewing files that changed from the base of the PR and between 8f75a72 and 48b8b0f.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • packages/chronicle/package.json
  • packages/chronicle/src/components/PrefetchProvider.tsx
  • packages/chronicle/src/lib/page-context.tsx
  • packages/chronicle/src/lib/preload.ts
  • packages/chronicle/src/server/entry-client.tsx

Comment thread packages/chronicle/src/components/PrefetchProvider.tsx Outdated
Raw getAttribute('href') can include hash fragments, query strings,
or relative paths that leak into the slug and cause bad API requests.
Resolve via new URL(href, location.href) and use pathname only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ClientProvider

QueryClientProvider stays in entry-client.tsx at app root.
PrefetchProvider moved to src/components/ui/ to match project structure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prefetching page data only relevant for docs content pages, not API
pages or landing page. Move from app root to DocsLayout which wraps
sidebar + content area.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@rsbh rsbh merged commit ceedc0f into main May 18, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants