如何优雅的将Next.js迁移到Vite

大家好啊,书接上文,Next.js 就是一坨,为此我把手里一个比较大的项目给迁移到了 Vite,整体迁移过程非常简单,不过一些比较机械的动作我交给了 AI,AI 还是好用啊🤤

首先,需要评估项目中使用的 Next.js 特性:

可以迁移的特性

  • 客户端渲染(CSR)
  • 静态页面
  • 路由系统
  • API 代理

需要替代方案的特性

  • 服务端渲染(SSR)→ 考虑使用 Vite SSR 插件或 Remix
  • API Routes → 迁移到独立后端或使用 Vite 代理
  • 图片优化(next/image)→ 使用 Vite 插件或第三方服务
  • 自动代码分割 → 使用 React.lazy() 和动态导入

这里我使用的是 App Router,所以迁移过去有点麻烦,重复的动作太多,Next.js 有两种路由,一种是 App Router 一种是 Pages Router,Vite 想要实现路由得安装 react-router 或者别的模块,装了后如下进行配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { Routes, Route, Navigate } from 'react-router-dom'
import { Suspense, lazy } from 'react'
import Loading from './components/Loading'

// 懒加载页面组件
const Home = lazy(() => import('./pages/home'))
const About = lazy(() => import('./pages/about'))
const PostDetail = lazy(() => import('./pages/posts/[id]'))

export default function Router() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/posts/:id" element={<PostDetail />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</Suspense>
)
}

然后就是动态参数获取

Next.js

1
2
3
4
5
6
import { useRouter } from 'next/router'

export default function PostPage() {
const router = useRouter()
const { id } = router.query
}

Vite + React Router

1
2
3
4
5
import { useParams } from 'react-router-dom'

export default function PostPage() {
const { id } = useParams<{ id: string }>()
}

接着就是导航方式,Next.js 的 link 必须用 <Link> 来进行包裹,迁移到别的项目后你想用 <a> 或者别的都可以

Next.js

1
2
3
4
5
import Link from 'next/link'
import { useRouter } from 'next/router'

<Link href="/about">About</Link>
router.push('/about')

Vite + React Router

1
2
3
4
5
import { Link, useNavigate } from 'react-router-dom'

<Link to="/about">About</Link>
const navigate = useNavigate()
navigate('/about')

环境变量迁移很简单,直接照搬即可

Next.js

1
2
3
4
5
// .env.local
NEXT_PUBLIC_API_URL=https://api.example.com

// 使用
const apiUrl = process.env.NEXT_PUBLIC_API_URL

Vite

1
2
3
4
5
// .env.local
VITE_API_URL=https://api.example.com

// 使用
const apiUrl = import.meta.env.VITE_API_URL

Next.js 的静态资源,官方说使用 <Image> 这个标签能最大化的利用图片、压缩图片啥的,不过用了也就那样,没啥鸟用

Next.js

1
2
import Image from 'next/image'
<Image src="/photo.jpg" width={500} height={300} alt="Photo" />

Vite

1
2
3
4
// 使用普通 img 标签
<img src="/photo.jpg" alt="Photo" className="w-[500px] h-[300px]" />

// 或使用第三方库如 react-image 进行优化

如果你的项目用到了SSR,则可以考虑Vite 的 SSR https://cn.vite.dev/guide/ssr:

1
2
3
4
5
6
7
8
9
10
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
plugins: [react()],
ssr: {
noExternal: ['react', 'react-dom'],
},
})