使用 TanStack Start 进行 SSR

在 Nitro 中使用 Vite 配合 TanStack Start 实现全栈 React。
server.ts
import handler, { createServerEntry } from "@tanstack/react-start/server-entry";

export default createServerEntry({
  fetch(request) {
    return handler.fetch(request);
  },
});

使用 Nitro 设置 TanStack Start,获得包含服务端渲染、基于文件的路由和集成 API 路由的全栈 React 框架体验。

概述

将 Nitro Vite 插件添加到你的 Vite 配置中

使用 TanStack Start 的服务端处理程序创建服务端入口

使用默认组件配置路由

使用基于文件的路由定义路由和 API 端点

1. 配置 Vite

将 Nitro、React、TanStack Start 和 Tailwind 插件添加到你的 Vite 配置中:

vite.config.mjs
import { defineConfig } from "vite";
import { nitro } from "nitro/vite";
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import viteReact from "@vitejs/plugin-react";
import viteTsConfigPaths from "vite-tsconfig-paths";
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [
    viteTsConfigPaths({ projects: ["./tsconfig.json"] }),
    tanstackStart(),
    viteReact(),
    tailwindcss(),
    nitro(),
  ],
  environments: {
    ssr: { build: { rollupOptions: { input: "./server.ts" } } },
  },
});

tanstackStart() 插件提供了完整的 SSR 集成,并自动处理客户端入口。使用 viteTsConfigPaths() 来启用 tsconfig 中的路径别名,如 ~/environments.ssr 选项指向服务端入口文件。

2. 创建服务端入口

创建一个使用 TanStack Start 处理程序的服务端入口:

server.ts
import handler, { createServerEntry } from "@tanstack/react-start/server-entry";

export default createServerEntry({
  fetch(request) {
    return handler.fetch(request);
  },
});

TanStack Start 自动处理 SSR。createServerEntry 包装器与 Nitro 的服务端入口格式集成,handler.fetch 处理所有传入的请求。

3. 配置路由

创建一个包含默认错误和未找到组件的路由工厂函数:

src/router.tsx
import { createRouter } from "@tanstack/react-router";
import { routeTree } from "./routeTree.gen.ts";

export function getRouter() {
  const router = createRouter({
    routeTree,
    defaultPreload: "intent",
    defaultErrorComponent: () => <div>Internal Server Error</div>,
    defaultNotFoundComponent: () => <div>Not Found</div>,
    scrollRestoration: true,
  });
  return router;
}

路由工厂配置了预加载行为、滚动恢复以及默认的错误/未找到组件。

4. 创建根路由

根路由定义了你的 HTML 外壳,包含 head 管理和脚本:

src/routes/__root.tsx
/// <reference types="vite/client" />
import { HeadContent, Link, Scripts, createRootRoute } from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
import * as React from "react";
import appCss from "~/styles/app.css?url";

export const Route = createRootRoute({
  head: () => ({
    meta: [
      { charSet: "utf8" },
      { name: "viewport", content: "width=device-width, initial-scale=1" },
    ],
    links: [{ rel: "stylesheet", href: appCss }],
    scripts: [{ src: "/customScript.js", type: "text/javascript" }],
  }),
  errorComponent: () => <h1>500: Internal Server Error</h1>,
  notFoundComponent: () => <h1>404: Page Not Found</h1>,
  shellComponent: RootDocument,
});

function RootDocument({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <head>
        <HeadContent />
      </head>
      <body>
        <div className="p-2 flex gap-2 text-lg">
          <Link to="/" activeProps={{ className: "font-bold" }} activeOptions={{ exact: true }}>
            Home
          </Link>{" "}
          <Link
            // @ts-ignore
            to="/this-route-does-not-exist"
            activeProps={{ className: "font-bold" }}
          >
            404
          </Link>
        </div>
        <hr />
        {children}
        <TanStackRouterDevtools position="bottom-right" />
        <Scripts />
      </body>
    </html>
  );
}

head() 函数中定义 meta 标签、样式表和脚本。shellComponent 提供了包裹所有页面的 HTML 文档外壳。使用 HeadContent 渲染 head 配置,使用 Scripts 注入用于水合的客户端 JavaScript。

5. 创建页面路由

页面路由定义了你的应用页面:

src/routes/index.tsx
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({ component: Home });

function Home() {
  return (
    <div className="p-2">
      <h3>欢迎回家!</h3>
      <a href="/api/test">/api/test</a>
    </div>
  );
}

API 路由

TanStack Start 支持 API 路由与页面路由并存。在 src/routes/api/ 中创建文件以定义 Nitro 自动提供服务的端点。

了解更多