mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-02 19:32:43 +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
3.9 KiB
3.9 KiB
split-lazy-routes: Use .lazy.tsx for Code Splitting
Priority: MEDIUM
Explanation
Split route components into .lazy.tsx files to reduce initial bundle size. The main route file keeps critical configuration (path, loaders, search validation), while lazy files contain components that load on-demand.
Bad Example
// routes/dashboard.tsx - Everything in one file
import { createFileRoute } from '@tanstack/react-router'
import { HeavyChartLibrary } from 'heavy-chart-library'
import { ComplexDataGrid } from 'complex-data-grid'
import { AnalyticsWidgets } from './components/AnalyticsWidgets'
export const Route = createFileRoute('/dashboard')({
loader: async ({ context }) => {
return context.queryClient.ensureQueryData(dashboardQueries.stats())
},
component: DashboardPage, // Entire component in main bundle
})
function DashboardPage() {
// Heavy components loaded even if user never visits dashboard
return (
<div>
<HeavyChartLibrary data={useLoaderData()} />
<ComplexDataGrid />
<AnalyticsWidgets />
</div>
)
}
Good Example
// routes/dashboard.tsx - Only critical config
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/dashboard')({
loader: async ({ context }) => {
return context.queryClient.ensureQueryData(dashboardQueries.stats())
},
// No component - it's in the lazy file
})
// routes/dashboard.lazy.tsx - Lazy-loaded component
import { createLazyFileRoute } from '@tanstack/react-router'
import { HeavyChartLibrary } from 'heavy-chart-library'
import { ComplexDataGrid } from 'complex-data-grid'
import { AnalyticsWidgets } from './components/AnalyticsWidgets'
export const Route = createLazyFileRoute('/dashboard')({
component: DashboardPage,
pendingComponent: DashboardSkeleton,
errorComponent: DashboardError,
})
function DashboardPage() {
const data = Route.useLoaderData()
return (
<div>
<HeavyChartLibrary data={data} />
<ComplexDataGrid />
<AnalyticsWidgets />
</div>
)
}
function DashboardSkeleton() {
return <div className="dashboard-skeleton">Loading dashboard...</div>
}
function DashboardError({ error }: { error: Error }) {
return <div>Failed to load dashboard: {error.message}</div>
}
What Goes Where
// Main route file (routes/example.tsx)
// - path configuration (implicit from file location)
// - validateSearch
// - beforeLoad (auth checks, redirects)
// - loader (data fetching)
// - loaderDeps
// - context manipulation
// - Static route data
// Lazy file (routes/example.lazy.tsx)
// - component
// - pendingComponent
// - errorComponent
// - notFoundComponent
Using getRouteApi in Lazy Components
// routes/posts/$postId.lazy.tsx
import { createLazyFileRoute, getRouteApi } from '@tanstack/react-router'
const route = getRouteApi('/posts/$postId')
export const Route = createLazyFileRoute('/posts/$postId')({
component: PostPage,
})
function PostPage() {
// Type-safe access without importing main route file
const { postId } = route.useParams()
const data = route.useLoaderData()
return <article>{/* ... */}</article>
}
Automatic Code Splitting
// vite.config.ts - Enable automatic splitting
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
export default defineConfig({
plugins: [
TanStackRouterVite({
autoCodeSplitting: true, // Automatically splits all route components
}),
react(),
],
})
// With autoCodeSplitting, you don't need .lazy.tsx files
// The plugin handles the splitting automatically
Context
- Lazy loading reduces initial bundle size significantly
- Loaders are NOT lazy - they need to run before rendering
createLazyFileRouteonly accepts component-related options- Use
getRouteApi()for type-safe hook access in lazy files - Consider
autoCodeSplitting: truefor simpler setup - Virtual routes auto-generate when only .lazy.tsx exists