mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-05 04:08:03 +00:00
shell: fish functions -> ~/.local/bin executables + bash/zsh ports; manage ~/.agents
- 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
This commit is contained in:
1 parent
6776366ce6
commit
6406208b35
637 files changed
+100297
-497
No files matched your search
@@ -0,0 +1,187 @@
|
||||
# cache-single-source: Let TanStack Query Manage Caching
|
||||
|
||||
## Priority: MEDIUM
|
||||
|
||||
## Explanation
|
||||
|
||||
When using TanStack Router with TanStack Query, let Query be the single source of truth for caching. Disable Router's built-in cache with `defaultPreloadStaleTime: 0` to avoid confusion about which cache is authoritative.
|
||||
|
||||
## Bad Example
|
||||
|
||||
```tsx
|
||||
// Both Router and Query caching enabled - confusing
|
||||
const router = createRouter({
|
||||
routeTree,
|
||||
context: { queryClient },
|
||||
// Default router caching enabled
|
||||
// defaultPreloadStaleTime: 30000 (default)
|
||||
})
|
||||
|
||||
export const Route = createFileRoute('/posts')({
|
||||
loader: async () => {
|
||||
// Fetches directly - cached by Router
|
||||
const posts = await fetchPosts()
|
||||
return { posts }
|
||||
},
|
||||
component: PostsPage,
|
||||
})
|
||||
|
||||
function PostsPage() {
|
||||
// Also uses Query cache - which is authoritative?
|
||||
const { data } = useQuery({
|
||||
queryKey: ['posts'],
|
||||
queryFn: fetchPosts,
|
||||
})
|
||||
|
||||
// Now there are TWO caches with potentially different data
|
||||
}
|
||||
```
|
||||
|
||||
## Good Example
|
||||
|
||||
```tsx
|
||||
// router.tsx - Disable router cache when using Query
|
||||
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: {
|
||||
staleTime: 1000 * 60 * 2, // 2 minutes
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const router = createRouter({
|
||||
routeTree,
|
||||
context: { queryClient },
|
||||
defaultPreload: 'intent',
|
||||
defaultPreloadStaleTime: 0, // Let Query manage caching
|
||||
scrollRestoration: true,
|
||||
})
|
||||
|
||||
setupRouterSsrQueryIntegration({
|
||||
router,
|
||||
queryClient,
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
// routes/posts.tsx
|
||||
export const Route = createFileRoute('/posts')({
|
||||
loader: async ({ context: { queryClient } }) => {
|
||||
// Query is the single cache source
|
||||
await queryClient.ensureQueryData(postQueries.all())
|
||||
// No return needed - data lives in Query cache
|
||||
},
|
||||
component: PostsPage,
|
||||
})
|
||||
|
||||
function PostsPage() {
|
||||
// Single source of truth
|
||||
const { data: posts } = useSuspenseQuery(postQueries.all())
|
||||
|
||||
return <PostList posts={posts} />
|
||||
}
|
||||
```
|
||||
|
||||
## Cache Comparison
|
||||
|
||||
| Feature | Router Cache | Query Cache |
|
||||
|---------|-------------|-------------|
|
||||
| Invalidation | Manual/time-based | Query keys, patterns |
|
||||
| Background refetch | No | Yes |
|
||||
| Optimistic updates | No | Yes |
|
||||
| Mutations | No built-in | Full support |
|
||||
| DevTools | Limited | Rich debugging |
|
||||
| Cross-route sharing | Full | Full |
|
||||
|
||||
## Good Example: Coordinated Caching Config
|
||||
|
||||
```tsx
|
||||
// router.tsx
|
||||
export function getRouter() {
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: 60 * 1000, // Fresh for 1 minute
|
||||
gcTime: 10 * 60 * 1000, // Cache for 10 minutes
|
||||
refetchOnWindowFocus: true, // Refetch when tab focused
|
||||
retry: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const router = createRouter({
|
||||
routeTree,
|
||||
context: { queryClient },
|
||||
defaultPreload: 'intent',
|
||||
defaultPreloadStaleTime: 0, // Router defers to Query
|
||||
scrollRestoration: true,
|
||||
defaultStructuralSharing: true,
|
||||
})
|
||||
|
||||
setupRouterSsrQueryIntegration({
|
||||
router,
|
||||
queryClient,
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
```
|
||||
|
||||
## Good Example: Preload Still Works
|
||||
|
||||
```tsx
|
||||
// Preloading still works - it just uses Query's cache
|
||||
export function getRouter() {
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
const router = createRouter({
|
||||
routeTree,
|
||||
context: { queryClient },
|
||||
defaultPreload: 'intent', // Preload on hover
|
||||
defaultPreloadStaleTime: 0, // Query decides if data is stale
|
||||
})
|
||||
|
||||
setupRouterSsrQueryIntegration({ router, queryClient })
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
// When user hovers a Link:
|
||||
// 1. Router triggers preload
|
||||
// 2. Loader runs ensureQueryData
|
||||
// 3. Query checks its cache - fresh? skip fetch. stale? refetch.
|
||||
// 4. User clicks - data already in Query cache
|
||||
```
|
||||
|
||||
## Mutation Invalidation
|
||||
|
||||
```tsx
|
||||
// Mutations properly invalidate the single cache
|
||||
const createPost = useMutation({
|
||||
mutationFn: submitPost,
|
||||
onSuccess: () => {
|
||||
// Invalidate Query cache - the single source
|
||||
queryClient.invalidateQueries({ queryKey: ['posts'] })
|
||||
|
||||
// Router automatically uses updated cache on next navigation
|
||||
navigate({ to: '/posts' })
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Context
|
||||
|
||||
- `defaultPreloadStaleTime: 0` means "always ask Query"
|
||||
- Query's staleTime/gcTime controls caching behavior
|
||||
- Preloading still works - just uses Query's cache
|
||||
- Mutations, optimistic updates, invalidation all work normally
|
||||
- DevTools show the single authoritative cache state
|
||||
- Use `setupRouterSsrQueryIntegration` for SSR hydration
|
||||
Reference in new issue
Block a user