tanstack-start
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese@json-render/tanstack-start
@json-render/tanstack-start
Use this integration when a TanStack Start app needs complete pages or routes
described by json-render specs.
当 TanStack Start 应用需要由 json-render 规范描述完整页面或路由时,使用此集成。
Install
安装
bash
npm install @json-render/core @json-render/react @json-render/tanstack-startbash
npm install @json-render/core @json-render/react @json-render/tanstack-startApplication Spec
应用规范
Include the server-safe built-in definitions in the generation catalog. The
renderer supplies their component implementations.
typescript
import { defineCatalog } from "@json-render/core";
import {
schema,
startComponentDefinitions,
} from "@json-render/tanstack-start/server";
const catalog = defineCatalog(schema, {
components: {
...startComponentDefinitions,
Card: cardDefinition,
Shell: shellDefinition,
Navigation: navigationDefinition,
Home: homeDefinition,
Post: postDefinition,
},
actions: {},
});Then use and TanStack Router route patterns:
StartAppSpectypescript
import type { StartAppSpec } from "@json-render/tanstack-start";
export const spec: StartAppSpec = {
metadata: {
title: { default: "Site", template: "%s | Site" },
},
layouts: {
main: {
root: "shell",
elements: {
shell: { type: "Shell", props: {}, children: ["nav", "slot"] },
nav: { type: "Navigation", props: {}, children: [] },
slot: { type: "Slot", props: {}, children: [] },
},
},
},
routes: {
"/": {
layout: "main",
metadata: { title: "Home" },
page: {
root: "home",
elements: {
home: { type: "Home", props: {}, children: [] },
},
},
},
"/posts/$slug": {
layout: "main",
loader: "post",
staticParams: [{ slug: "hello" }],
page: {
root: "post",
elements: {
post: {
type: "Post",
props: { value: { $state: "/post" } },
children: [],
},
},
},
},
},
};Routes use for named parameters and for a splat.
Splat loader parameters are slash-delimited strings under . Escape
route-key slashes as when generating RFC 6902 patches.
/posts/$slug/docs/$_splat~1Every layout needs a element. Declare and through
; do not require consumers to register React
implementations for them.
SlotSlotLinkstartComponentDefinitions在生成目录中包含服务端安全的内置定义。渲染器提供它们的组件实现。
typescript
import { defineCatalog } from "@json-render/core";
import {
schema,
startComponentDefinitions,
} from "@json-render/tanstack-start/server";
const catalog = defineCatalog(schema, {
components: {
...startComponentDefinitions,
Card: cardDefinition,
Shell: shellDefinition,
Navigation: navigationDefinition,
Home: homeDefinition,
Post: postDefinition,
},
actions: {},
});然后使用 和 TanStack Router 路由模式:
StartAppSpectypescript
import type { StartAppSpec } from "@json-render/tanstack-start";
export const spec: StartAppSpec = {
metadata: {
title: { default: "Site", template: "%s | Site" },
},
layouts: {
main: {
root: "shell",
elements: {
shell: { type: "Shell", props: {}, children: ["nav", "slot"] },
nav: { type: "Navigation", props: {}, children: [] },
slot: { type: "Slot", props: {}, children: [] },
},
},
},
routes: {
"/": {
layout: "main",
metadata: { title: "Home" },
page: {
root: "home",
elements: {
home: { type: "Home", props: {}, children: [] },
},
},
},
"/posts/$slug": {
layout: "main",
loader: "post",
staticParams: [{ slug: "hello" }],
page: {
root: "post",
elements: {
post: {
type: "Post",
props: { value: { $state: "/post" } },
children: [],
},
},
},
},
},
};路由使用 表示命名参数, 用于 splat 路由。Splat 加载器参数是 下以斜杠分隔的字符串。生成 RFC 6902 补丁时,将路由键中的斜杠转义为 。
/posts/$slug/docs/$_splat~1每个布局都需要一个 元素。通过 声明 和 ;无需让使用者注册它们的 React 实现。
SlotstartComponentDefinitionsSlotLinkServer Helpers
服务端辅助工具
typescript
import { createStartApp } from "@json-render/tanstack-start/server";
export const { getPageData, getHead, getStaticPaths } = createStartApp({
spec,
loaders: {
post: async ({ slug }) => ({ post: await getPost(slug as string) }),
},
});State merge precedence is application state, layout state, page state, then
loader data. merges app and route metadata into TanStack and
descriptors. includes static routes plus dynamic
routes with . Convert its strings to objects for
TanStack Start's top-level plugin option. Loader params are URL-decoded,
while values from are URL-encoded in generated paths.
Route matching treats trailing slashes as optional and accepts encoded or
decoded pathname representations so loader data and metadata resolve the same
static route.
getHeadmetalinksgetStaticPathsstaticParams{ path }pagesstaticParamstypescript
import { createStartApp } from "@json-render/tanstack-start/server";
export const { getPageData, getHead, getStaticPaths } = createStartApp({
spec,
loaders: {
post: async ({ slug }) => ({ post: await getPost(slug as string) }),
},
});状态合并优先级为:应用状态、布局状态、页面状态,最后是加载器数据。 将应用和路由元数据合并到 TanStack 的 和 描述符中。 包含静态路由以及带有 的动态路由。将其返回的字符串转换为 对象,可用于 TanStack Start 的顶层 插件选项。加载器参数是经过 URL 解码的,而 中的值在生成的路径中是经过 URL 编码的。路由匹配将尾部斜杠视为可选,同时接受编码或解码后的路径名表示,因此加载器数据和元数据会解析到同一个静态路由。
getHeadmetalinksgetStaticPathsstaticParams{ path }pagesstaticParamsRoute Wiring
路由接入
tsx
import { createFileRoute, notFound } from "@tanstack/react-router";
import {
PageRenderer,
StartErrorBoundary,
StartLoading,
StartNotFound,
} from "@json-render/tanstack-start";
import { getHead, getPageData } from "@/lib/json-app";
export const Route = createFileRoute("/$")({
loader: async ({ location }) => {
const data = await getPageData({ pathname: location.pathname });
if (!data) throw notFound();
return data;
},
head: ({ match }) => getHead({ pathname: match.pathname }),
component: () => <PageRenderer {...Route.useLoaderData()} />,
pendingComponent: StartLoading,
errorComponent: StartErrorBoundary,
notFoundComponent: StartNotFound,
});TanStack Router loaders run on both the server and client. If a spec factory or
named loader uses credentials, database clients, or server-only imports, wrap
and in a TanStack Start ; do not import
that server code directly into an isomorphic route loader.
getPageDatagetHeadcreateServerFntsx
import { createFileRoute, notFound } from "@tanstack/react-router";
import {
PageRenderer,
StartErrorBoundary,
StartLoading,
StartNotFound,
} from "@json-render/tanstack-start";
import { getHead, getPageData } from "@/lib/json-app";
export const Route = createFileRoute("/$")({
loader: async ({ location }) => {
const data = await getPageData({ pathname: location.pathname });
if (!data) throw notFound();
return data;
},
head: ({ match }) => getHead({ pathname: match.pathname }),
component: () => <PageRenderer {...Route.useLoaderData()} />,
pendingComponent: StartLoading,
errorComponent: StartErrorBoundary,
notFoundComponent: StartNotFound,
});TanStack Router 加载器在服务端和客户端都会运行。如果规范工厂或命名加载器使用了凭据、数据库客户端或仅服务端导入的内容,请将 和 包装在 TanStack Start 的 中;不要将该服务端代码直接导入到同构路由加载器中。
getPageDatagetHeadcreateServerFnRoot Provider
根 Provider
Wrap the root route's with . Render so
metadata from reaches the document.
OutletStartAppProviderHeadContentgetHeadtsx
import {
createRootRoute,
HeadContent,
Outlet,
Scripts,
} from "@tanstack/react-router";
import { StartAppProvider } from "@json-render/tanstack-start";
import { spec } from "@/lib/spec";
export const Route = createRootRoute({
component: () => (
<html lang="en">
<head>
<HeadContent />
</head>
<body>
<StartAppProvider
registry={registry}
handlers={handlers}
spec={spec}
>
<Outlet />
</StartAppProvider>
<Scripts />
</body>
</html>
),
});Use , , and for TanStack
Router's , , and options.
When receives , each component selects the matched
route's corresponding fallback. Explicit fallback props override that lookup.
Pass named implementations through .
The default error boundary invalidates the router and reruns a failed loader
when the user selects Try again.
StartLoadingStartErrorBoundaryStartNotFoundpendingComponenterrorComponentnotFoundComponentStartAppProviderspec$computedStartAppProvider.functionsImport React components from . Import ,
, , , and static path helpers from
.
@json-render/tanstack-startschemacreateStartAppmatchRouteresolveMetadata@json-render/tanstack-start/server用 包裹根路由的 。渲染 ,以便 返回的元数据能作用于文档。
StartAppProviderOutletHeadContentgetHeadtsx
import {
createRootRoute,
HeadContent,
Outlet,
Scripts,
} from "@tanstack/react-router";
import { StartAppProvider } from "@json-render/tanstack-start";
import { spec } from "@/lib/spec";
export const Route = createRootRoute({
component: () => (
<html lang="en">
<head>
<HeadContent />
</head>
<body>
<StartAppProvider
registry={registry}
handlers={handlers}
spec={spec}
>
<Outlet />
</StartAppProvider>
<Scripts />
</body>
</html>
),
});将 、 和 用于 TanStack Router 的 、 和 选项。当 接收到 时,每个组件会选择匹配路由对应的回退内容。显式的回退属性会覆盖该查找逻辑。通过 传递命名的 实现。当用户选择重试时,默认的错误边界会使路由失效并重新运行失败的加载器。
StartLoadingStartErrorBoundaryStartNotFoundpendingComponenterrorComponentnotFoundComponentStartAppProviderspecStartAppProvider.functions$computed从 导入 React 组件。从 导入 、、、 以及静态路径辅助函数。
@json-render/tanstack-start@json-render/tanstack-start/serverschemacreateStartAppmatchRouteresolveMetadata