mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-03 11:37:36 +00:00
- 16 cross-shell utilities converted to sh/bash chezmoi executables: ai c2p cp-appid extract_agents fab gdc gh-sonr-org-migrate ghg-clone ghn gho git-summary launch_omp_livediff_overlay lc-elir mdcp mdp pj (ghg-clone not named ghg: unrelated cargo binary owns that name) - cwd/history helpers stay per-shell: yy c cd clip-last + ghg/ghn/gho cd-wrappers in bash/functions/ and zsh/functions/, loaded by rc files - fish keeps only shell-state functions; converted ones now hit PATH - cp-appid ignore gating moved to .local/bin path - dot_agents/skills: 82 skills materialized from dotstate storage so dot_claude skill symlinks resolve on fresh bootstrap; dotstate profile/symlinks.json released .agents/skills .bashrc .zshrc
5.4 KiB
5.4 KiB
ssr-dehydrate-hydrate: Configure SSR Query Integration
Priority: CRITICAL
Explanation
Use @tanstack/react-router-ssr-query to automatically handle SSR dehydration/hydration between TanStack Router and TanStack Query. This package automates cache transfer, streaming, and redirect handling.
Bad Example
// Manual dehydration - verbose and error-prone
import { dehydrate, hydrate } from '@tanstack/react-query'
const router = createRouter({
routeTree,
context: { queryClient },
// Manual approach - lots of boilerplate
dehydrate: () => ({
queryClientState: dehydrate(queryClient),
}),
hydrate: (dehydrated) => {
hydrate(queryClient, dehydrated.queryClientState)
},
Wrap: ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
),
})
Good Example: Modern SSR Integration
// router.tsx
import { QueryClient } from '@tanstack/react-query'
import { createRouter } from '@tanstack/react-router'
import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'
import { routeTree } from './routeTree.gen'
export function getRouter() {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
staleTime: 1000 * 60 * 2, // 2 minutes
},
},
})
const router = createRouter({
routeTree,
context: { queryClient },
defaultPreload: 'intent',
defaultPreloadStaleTime: 0, // Let Query manage cache freshness
scrollRestoration: true,
defaultStructuralSharing: true,
})
// Automatic SSR dehydration/hydration
setupRouterSsrQueryIntegration({
router,
queryClient,
handleRedirects: true, // Intercept redirects from queries/mutations
wrapQueryClient: true, // Auto-wrap with QueryClientProvider
})
return router
}
Good Example: With Error and NotFound Components
import { DefaultCatchBoundary } from '@/components/DefaultCatchBoundary'
import { DefaultNotFound } from '@/components/DefaultNotFound'
export function getRouter() {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
staleTime: 1000 * 60 * 2,
},
},
})
const router = createRouter({
routeTree,
context: { queryClient, user: null },
defaultPreload: 'intent',
defaultPreloadStaleTime: 0,
defaultErrorComponent: DefaultCatchBoundary,
defaultNotFoundComponent: DefaultNotFound,
scrollRestoration: true,
defaultStructuralSharing: true,
})
setupRouterSsrQueryIntegration({
router,
queryClient,
handleRedirects: true,
wrapQueryClient: true,
})
return router
}
Good Example: Custom QueryClientProvider
// If you need custom provider setup (e.g., for DevTools)
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
export function getRouter() {
const queryClient = new QueryClient()
const router = createRouter({
routeTree,
context: { queryClient },
defaultPreload: 'intent',
defaultPreloadStaleTime: 0,
scrollRestoration: true,
})
setupRouterSsrQueryIntegration({
router,
queryClient,
handleRedirects: true,
wrapQueryClient: false, // We'll provide our own
})
// Custom wrapper with DevTools
router.options.Wrap = ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
{process.env.NODE_ENV === 'development' && (
<ReactQueryDevtools initialIsOpen={false} />
)}
</QueryClientProvider>
)
return router
}
Good Example: Vite Configuration
// vite.config.ts
import { tanstackStart } from "@tanstack/start/plugin/vite"
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
export default defineConfig({
plugins: [
tanstackStart(), // Handles SSR entry points automatically
react(),
],
})
TanStack Start handles client hydration and SSR automatically via the Vite plugin. No separate client.tsx or ssr.tsx files are needed.
setupRouterSsrQueryIntegration Options
| Option | Type | Default | Description |
|---|---|---|---|
router |
Router | Required | Your router instance |
queryClient |
QueryClient | Required | Your QueryClient instance |
handleRedirects |
boolean | true |
Intercept and handle redirects from queries/mutations |
wrapQueryClient |
boolean | true |
Wrap router with QueryClientProvider automatically |
SSR Data Flow
Server:
1. Request received
2. getRouter() creates fresh QueryClient + Router
3. setupRouterSsrQueryIntegration connects them
4. Router matches routes, runs loaders
5. Loaders call ensureQueryData → data cached
6. Integration auto-dehydrates QueryClient state
7. HTML + serialized state streamed to client
Client:
1. HTML rendered (React hydrates)
2. getRouter() creates fresh QueryClient + Router
3. Integration auto-hydrates state from server
4. useSuspenseQuery finds data in cache - no refetch!
5. App is interactive with data already loaded
Context
- Install:
npm install @tanstack/react-router-ssr-query - Creates fresh QueryClient per request (required for SSR)
- Handles streaming of queries that resolve during render
- Set
defaultPreloadStaleTime: 0to let Query manage freshness - Each SSR request needs its own router instance via
getRouter() - The integration handles all dehydration/hydration automatically