从Next.js迁移到TanStack Router的完整指南
前言
在现代前端开发中,路由管理是构建单页应用(SPA)的核心部分。TanStack Router作为新一代的路由解决方案,提供了更灵活、更强大的路由功能。本文将详细介绍如何从Next.js迁移到TanStack Router,帮助开发者理解两者之间的差异并顺利完成迁移。
准备工作
在开始迁移前,确保你的项目结构符合以下标准:
项目目录结构
├── package.json
├── src
│ └── app
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
└── tsconfig.json
如果你的项目结构不同,需要先调整到类似结构。这个结构代表了典型的Next.js应用布局,使用App Router模式。
迁移步骤详解
第一步:移除Next.js相关依赖
首先需要清理Next.js特有的依赖和配置文件:
npm uninstall @tailwindcss/postcss next
rm postcss.config.* next.config.*
这一步会移除Next.js核心包和相关的构建配置。
第二步:安装TanStack Router和Vite
TanStack Router需要搭配Vite使用,安装必要的依赖:
npm i @tanstack/react-router@alpha @tanstack/react-start@alpha vite
npm i -D @tailwindcss/vite tailwindcss vite-tsconfig-paths
这里安装了:
- TanStack Router核心库
- TanStack Start集成工具
- Vite构建工具
- Tailwind CSS相关支持
第三步:配置Vite项目
更新项目配置文件以适应新的构建系统:
- 修改
package.json
:
{
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"start": "node .output/server/index.mjs"
}
}
- 创建
vite.config.ts
:
import tailwindcss from '@tailwindcss/vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
server: {
port: 3000,
},
plugins: [
tailwindcss(),
tsconfigPaths(),
tanstackStart({
tsr: {
routesDirectory: 'src/app',
},
}),
],
})
关键点说明:
routesDirectory
指定了路由文件目录,保持与Next.js一致的src/app
- 集成了Tailwind CSS支持
- 启用了路径别名解析
第四步:重构根布局
Next.js使用layout.tsx
作为根布局,TanStack Router使用__root.tsx
:
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from "@tanstack/react-router"
import "./globals.css"
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: "utf-8" },
{ name: "viewport", content: "width=device-width, initial-scale=1" },
{ title: "TanStack Start Starter" }
],
}),
component: RootLayout,
})
function RootLayout() {
return (
<html lang="en">
<head>
<HeadContent />
</head>
<body>
<Outlet />
<Scripts />
</body>
</html>
)
}
主要变化:
- 使用
createRootRoute
创建根路由 - 通过
head
配置替代Next.js的metadata - 使用
Outlet
作为子路由的渲染出口
第五步:重构首页
将Next.js的page.tsx
转换为TanStack Router的index.tsx
:
export const Route = createFileRoute({
component: Home,
})
function Home() {
return (
<main className="min-h-dvh w-screen flex items-center justify-center flex-col gap-y-4 p-4">
<img
className="max-w-sm w-full"
src="https://raw.githubusercontent.com/tanstack/tanstack.com/main/src/images/splash-dark.png"
alt="TanStack Logo"
/>
<h1>
<span className="line-through">Next.js</span> TanStack Start
</h1>
<a
className="bg-foreground text-background rounded-full px-4 py-1 hover:opacity-90"
href="https://tanstack.com/start/latest"
target="_blank"
>
Docs
</a>
</main>
)
}
关键变化:
- 使用
createFileRoute
定义路由 - 组件不再需要默认导出
第六步:创建路由配置
在src/router.tsx
中定义应用路由:
import { createRouter as createTanStackRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export function createRouter() {
const router = createTanStackRouter({
routeTree,
scrollRestoration: true,
})
return router
}
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}
这个文件是TanStack Router的核心配置,可以在这里设置:
- 路由预加载策略
- 数据缓存策略
- 滚动恢复行为等
第七步:验证迁移
运行开发服务器:
npm run dev
访问http://localhost:3000
,应该能看到应用正常运行。
高级迁移指南
路由结构对比
| 路由类型 | Next.js路径 | TanStack Router路径 | |---------------|----------------------------|--------------------------| | 根布局 | src/app/layout.tsx
| src/app/__root.tsx
| | 首页 | src/app/page.tsx
| src/app/index.tsx
| | 静态路由 | src/app/posts/page.tsx
| src/app/posts.tsx
| | 动态路由 | src/app/posts/[slug]/page.tsx
| src/app/posts/$slug.tsx
| | 全匹配路由 | src/app/posts/[...slug]/page.tsx
| src/app/posts/$.tsx
| | API路由 | src/app/api/endpoint/route.ts
| src/app/api/endpoint.ts
|
动态路由参数获取
在TanStack Router中获取动态参数:
export const Route = createFileRoute({
component: Page,
})
function Page() {
const { slug } = Route.useParams()
return <div>My Post: {slug}</div>
}
对于全匹配路由,使用_splat
获取参数:
const { _splat } = Route.useParams()
链接组件
TanStack Router提供了自己的Link
组件:
import { Link } from "@tanstack/react-router"
function Component() {
return <Link to="/dashboard">Dashboard</Link>
}
服务端功能
TanStack Router的服务端函数定义:
import { createServerFn } from "@tanstack/react-start"
export const create = createServerFn().handler(async () => {
return true
})
字体处理
替代Next.js的字体方案,使用CSS优先方法:
- 安装字体包:
npm i -D @fontsource-variable/dm-sans @fontsource-variable/jetbrains-mono
- 在CSS中引入:
@import '@fontsource-variable/dm-sans';
@import '@fontsource-variable/jetbrains-mono';
@theme inline {
--font-sans: 'DM Sans Variable', sans-serif;
--font-mono: 'JetBrains Mono Variable', monospace;
}
数据获取
TanStack Router推荐使用路由加载器:
export const Route = createFileRoute({
component: Page,
loader: async () => {
const res = await fetch('https://api.example.com/blog')
return res.json()
},
})
function Page() {
const posts = Route.useLoaderData()
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
总结
从Next.js迁移到TanStack Router涉及多个方面的调整,包括路由定义、布局系统、数据获取等。本文详细介绍了每个关键步骤的转换方法,帮助开发者理解两种路由系统的差异。TanStack Router提供了更灵活的路由配置和更强大的功能,适合需要精细控制路由行为的中大型应用。
迁移完成后,你可以充分利用TanStack Router提供的先进特性,如嵌套路由、精细的路由预加载和数据缓存策略等,来提升应用性能和开发体验。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考