con un clic
code-splitting
>-
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
>-
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
Select and load the correct TanStack skill for tku-sparring tasks. Use when users ask about TanStack Router, React Start, Start server functions or middleware, SSR, search params, path params, navigation, loaders, or TanStack Query best practices.
TanStack Query (React Query) best practices for data fetching, caching, mutations, and server state management. Activate when building data-driven React applications with server state.
Survey any codebase as a senior advisor and produce prioritized, self-contained implementation plans for OTHER models/agents to execute. Strictly read-only on source code — never implements, fixes, or refactors anything itself. Use when asked to audit a codebase, find improvement opportunities (bugs, security, performance, test coverage, tech debt, migrations, DX), suggest features or where to take the project next (roadmap, product direction), or generate handoff plans for another agent to implement.
TanStack Start best practices for full-stack React applications. Server functions, middleware, SSR, authentication, and deployment patterns. Activate when building full-stack apps with TanStack Start.
Implement, review, debug, and refactor TanStack Start React Server Components in React 19 apps. Use when tasks mention @tanstack/react-start/rsc, renderServerComponent, createCompositeComponent, CompositeComponent, renderToReadableStream, createFromReadableStream, createFromFetch, Composite Components, React Flight streams, loader or query owned RSC caching, router.invalidate, structuralSharing: false, selective SSR, stale names like renderRsc or .validator, or migration from Next App Router RSC patterns. Do not use for generic SSR or non-TanStack RSC frameworks except brief comparison.
React bindings for TanStack Start: createStart, StartClient, StartServer, React-specific imports, re-exports from @tanstack/react-router, full project setup with React, useServerFn hook.
| name | code-splitting |
| description | >- |
TanStack Router separates route code into critical (required to match and start loading) and non-critical (can be lazy-loaded). The bundler plugin can split automatically, or you can split manually with .lazy.tsx files.
CRITICAL: Never
exportcomponent functions from route files — exported functions are included in the main bundle and bypass code splitting entirely.
CRITICAL: Use
getRouteApi('/path')in code-split files, NOTimport { Route } from './route'. Importing Route defeats code splitting.
validateSearchloader, beforeLoadcomponenterrorComponentpendingComponentnotFoundComponentThe
loaderis NOT split by default. It is already async, so splitting it adds a double async cost: fetch the chunk, then execute the loader. Only split the loader if you have a specific reason.
Enable autoCodeSplitting: true in the bundler plugin. This is the recommended approach.
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
plugins: [
// TanStack Router plugin MUST come before the framework plugin
tanstackRouter({
autoCodeSplitting: true,
}),
react(),
],
})
With this enabled, route files are automatically transformed. Components are split into separate chunks; loaders stay in the main bundle. No .lazy.tsx files needed.
// src/routes/posts.tsx — everything in one file, splitting is automatic
import { createFileRoute } from '@tanstack/react-router'
import { fetchPosts } from '../api'
export const Route = createFileRoute('/posts')({
loader: fetchPosts,
component: PostsComponent,
})
// NOT exported — this is critical for automatic code splitting to work
function PostsComponent() {
const posts = Route.useLoaderData()
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
.lazy.tsxIf you cannot use automatic code splitting (e.g. CLI-only, no bundler plugin), split manually into two files:
// src/routes/posts.tsx — critical route config only
import { createFileRoute } from '@tanstack/react-router'
import { fetchPosts } from '../api'
export const Route = createFileRoute('/posts')({
loader: fetchPosts,
})
// src/routes/posts.lazy.tsx — non-critical (lazy-loaded)
import { createLazyFileRoute } from '@tanstack/react-router'
export const Route = createLazyFileRoute('/posts')({
component: PostsComponent,
})
function PostsComponent() {
// Use getRouteApi to access typed hooks without importing Route
return <div>Posts</div>
}
createLazyFileRoute supports only: component, errorComponent, pendingComponent, notFoundComponent.
If splitting leaves the critical route file empty, delete it entirely. A virtual route is auto-generated in routeTree.gen.ts:
// src/routes/about.lazy.tsx — no about.tsx needed
import { createLazyFileRoute } from '@tanstack/react-router'
export const Route = createLazyFileRoute('/about')({
component: () => <h1>About Us</h1>,
})
For code-based (non-file-based) routing, use createLazyRoute and the .lazy() method:
// src/posts.lazy.tsx
import { createLazyRoute } from '@tanstack/react-router'
export const Route = createLazyRoute('/posts')({
component: PostsComponent,
})
function PostsComponent() {
return <div>Posts</div>
}
// src/app.tsx
import { createRoute } from '@tanstack/react-router'
const postsRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/posts',
}).lazy(() => import('./posts.lazy').then((d) => d.Route))
getRouteApiWhen your component lives in a separate file, use getRouteApi to get typed access to route hooks without importing the Route object:
// src/routes/posts.lazy.tsx
import { createLazyFileRoute, getRouteApi } from '@tanstack/react-router'
const routeApi = getRouteApi('/posts')
export const Route = createLazyFileRoute('/posts')({
component: PostsComponent,
})
function PostsComponent() {
const posts = routeApi.useLoaderData()
const { page } = routeApi.useSearch()
const params = routeApi.useParams()
const context = routeApi.useRouteContext()
return <div>Posts page {page}</div>
}
getRouteApi provides: useLoaderData, useLoaderDeps, useMatch, useParams, useRouteContext, useSearch.
codeSplitGroupingsOverride split behavior for a specific route by adding codeSplitGroupings directly in the route file:
// src/routes/posts.tsx
import { createFileRoute } from '@tanstack/react-router'
import { loadPostsData } from './-heavy-posts-utils'
export const Route = createFileRoute('/posts')({
// Bundle loader and component together for this route
codeSplitGroupings: [['loader', 'component']],
loader: () => loadPostsData(),
component: PostsComponent,
})
function PostsComponent() {
const data = Route.useLoaderData()
return <div>{data.title}</div>
}
defaultBehavior — Change Default Groupings// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
plugins: [
tanstackRouter({
autoCodeSplitting: true,
codeSplittingOptions: {
defaultBehavior: [
// Bundle all UI components into one chunk
[
'component',
'pendingComponent',
'errorComponent',
'notFoundComponent',
],
],
},
}),
],
})
splitBehavior — Programmatic Per-Route Logic// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
plugins: [
tanstackRouter({
autoCodeSplitting: true,
codeSplittingOptions: {
splitBehavior: ({ routeId }) => {
if (routeId.startsWith('/posts')) {
return [['loader', 'component']]
}
// All other routes use defaultBehavior
},
},
}),
],
})
codeSplitGroupings (highest)splitBehavior functiondefaultBehavior option (lowest)// WRONG — export puts PostsComponent in the main bundle
export function PostsComponent() {
return <div>Posts</div>
}
// CORRECT — no export, function stays in the split chunk
function PostsComponent() {
return <div>Posts</div>
}
__root.tsx does not support code splitting. It is always rendered regardless of the current route. Do not create __root.lazy.tsx.
// AVOID unless you have a specific reason
codeSplittingOptions: {
defaultBehavior: [
['loader'], // Fetch chunk THEN execute loader = two network waterfalls
['component'],
],
}
// PREFERRED — loader stays in main bundle (default behavior)
codeSplittingOptions: {
defaultBehavior: [
['component'],
['errorComponent'],
['notFoundComponent'],
],
}
// WRONG — importing Route pulls route config into the lazy chunk
import { Route } from './posts.tsx'
const data = Route.useLoaderData()
// CORRECT — getRouteApi gives typed hooks without pulling in the route
import { getRouteApi } from '@tanstack/react-router'
const routeApi = getRouteApi('/posts')
const data = routeApi.useLoaderData()
getRouteApi is the type-safe way to access hooks from split files.