字
字节笔记本
2026年5月3日
TanStack Start - 从 Next.js 迁移指南
API中转
¥120
本文提供从 Next.js App Router 迁移到 TanStack Start 的完整指南,帮助你逐步完成框架切换。
迁移概述
本指南提供从 Next.js App Router 迁移到 TanStack Start 的逐步过程。
前置条件
假设你的项目结构如下:
txt
├── next.config.ts
├── package.json
├── postcss.config.mjs
├── public/
│ ├── file.svg
│ └── ...
├── src/
│ └── app/
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
└── tsconfig.json逐步迁移(基础)
步骤 1: 移除 Next.js
卸载 Next.js 并删除相关配置文件:
bash
npm uninstall @tailwindcss/postcss next
rm postcss.config.* next.config.*步骤 2: 安装必需依赖
TanStack Start 基于 Vite 和 TanStack Router:
bash
npm i @tanstack/react-router @tanstack/react-startTailwind CSS 和路径别名解析:
bash
npm i -D vite @vitejs/plugin-react @tailwindcss/vite tailwindcss vite-tsconfig-paths步骤 3: 更新项目配置
package.json:
json
{
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"start": "node .output/server/index.mjs"
}
}vite.config.ts:
typescript
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
server: {
port: 3000,
},
plugins: [
tailwindcss(),
tsconfigPaths(),
tanstackStart({
srcDirectory: 'src',
router: {
routesDirectory: 'app',
},
}),
viteReact(),
],
})步骤 4: 适配根布局
创建 src/app/__root.tsx 文件(替代 layout.tsx):
Next.js (layout.tsx):
tsx
import type { Metadata } from "next"
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
}
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}TanStack Start (__root.tsx):
tsx
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from "@tanstack/react-router"
import appCss from "./globals.css?url"
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: "utf-8" },
{
name: "viewport",
content: "width=device-width, initial-scale=1",
},
{ title: "TanStack Start Starter" }
],
links: [
{
rel: 'stylesheet',
href: appCss,
},
],
}),
component: RootLayout,
})
function RootLayout() {
return (
<html lang="en">
<head>
<HeadContent />
</head>
<body>
<Outlet />
<Scripts />
</body>
</html>
)
}步骤 5: 适配首页
创建 src/app/index.tsx(替代 page.tsx):
tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
component: Home,
})
function Home() {
return <main>...</main>
}步骤 6: 创建路由配置
创建 src/router.tsx:
tsx
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export function getRouter() {
const router = createRouter({
routeTree,
scrollRestoration: true,
})
return router
}步骤 7: 验证迁移
bash
npm run dev高级迁移步骤
路由概念对比
| 路由示例 | Next.js | TanStack Start |
|---|---|---|
| 根布局 | src/app/layout.tsx | src/app/__root.tsx |
/ 首页 | src/app/page.tsx | src/app/index.tsx |
/posts 静态 | src/app/posts/page.tsx | src/app/posts.tsx |
/posts/[slug] 动态 | src/app/posts/[slug]/page.tsx | src/app/posts/$slug.tsx |
/posts/[...slug] 捕获 | src/app/posts/[...slug]/page.tsx | src/app/posts/$.tsx |
/api/endpoint API | src/app/api/endpoint/route.ts | src/app/api/endpoint.ts |
动态和捕获路由
Next.js:
tsx
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
return <div>Post: {slug}</div>
}TanStack Start:
tsx
export const Route = createFileRoute('/app/posts/$slug')({
component: Page,
})
function Page() {
const { slug } = Route.useParams()
return <div>Post: {slug}</div>
}Server Functions(服务端函数)
Next.js Server Actions:
tsx
'use server'
export const create = async () => {
return true
}TanStack Start Server Functions:
tsx
import { createServerFn } from "@tanstack/react-start"
export const create = createServerFn().handler(async () => {
return true
})Fetching Data(数据获取)
Next.js:
tsx
export default async function Page() {
const data = await fetch('https://api.vercel.app/blog')
const posts = await data.json()
return <ul>...</ul>
}TanStack Start:
tsx
export const Route = createFileRoute('/')({
component: Page,
loader: async () => {
const res = await fetch('https://api.vercel.app/blog')
return res.json()
},
})
function Page() {
const posts = Route.useLoaderData()
return <ul>...</ul>
}迁移检查清单
- 移除 Next.js 和相关配置
- 安装 TanStack Start 依赖
- 更新 vite.config.ts
- 转换 layout.tsx → __root.tsx
- 转换 page.tsx → index.tsx
- 创建 router.tsx
- 更新动态路由语法
- 迁移 Links 组件
- 迁移 Server Actions → Server Functions
- 迁移数据获取到 loader
- 测试验证
关键差异
| 特性 | Next.js | TanStack Start |
|---|---|---|
| 文件约定 | page.tsx, layout.tsx | index.tsx, __root.tsx |
| 动态路由 | [param] | $param |
| 数据获取 | 组件内 async | loader 函数 |
| 服务端函数 | 'use server' | createServerFn |
| 链接 | Link href | Link to |
分享: