记得上次用nextjs写博客,13才刚出,那是我第一次接触这个框架,边写边翻文档,感受着它带来的方便和社区的活力,伸手就来的组件,UI又好看,代码写起来也很优雅,我在毕业找工作的时候甚至以此为目标,希望目标公司的技术栈是使用nextjs。时光飞逝,如今已经到了15版本,升级的过程也让我感受到了技术的进步和社区的不断壮大。接下来,我将分享一下从Nextjs 13升级到15的过程和遇到的一些问题,希望对大家有所帮助。
Next.js 14 和 15 的主要升级内容
- 优化的 Server Components:更好地支持 React Server Components,自动进行代码分割和优化加载策略,进一步提升页面加载速度。
- Streaming 和 Suspense 改进:流式渲染和 Suspense 的改进使页面更早显示出内容,对 SEO 和用户体验都更友好。
- 新的 Router 特性:更灵活的路由配置,包括动态段路由(segment routing),为路由设计和导航提供更多选择。
- TurboPack 构建系统(实验性):相比 Webpack,TurboPack 编译速度更快,提升了开发和构建性能。
- App Router 进一步完善:App Router 和 Pages Router 的整合更清晰,特别是对于大型应用或 SSR/CSR 混合需求的应用来说,维护和配置更加方便。
- 内置国际化支持改进:支持更多的本地化配置选择,让多语言内容更易管理。
- 更强的 TypeScript 支持:内置 TypeScript 改进,减少配置需求,并且更贴近最新的 TypeScript 版本特性。
升级后对博客的潜在改进
- 更快的加载速度:Server Components 和流式渲染能让页面在服务器端预加载,速度更快,对读者友好。
- 改进的 SEO:App Router 提升了 SEO 支持。流式渲染可以让内容更早地出现在页面上,增强 SEO 效果。
- 可扩展性更强的路由:若你有意增设文章分类、标签页、动态内容等,新的路由系统能让这些变得更灵活。
- 代码分割和自动优化:通过自动代码分割,Next.js 14 和 15 在处理代码优化方面更智能,能帮助你减少博客的打包体积和加载时间。
更新内容可在文档查看version 15
升级后解决报错
pnpm up next@latest react@rc react-dom@rc eslint-config-next@latest
运行的时候控制台会告知,node版本需要>=18.18.0,我原先用的18.16.0,故而吧node也升级了(14用的是18.17.0),升级完后运行报错,R3FBox 是我封装的一个 3D 库,里面都是 three/fiber 相关的,为了增加首次加载的性能,确保 3D 组件渲染的时候不报错,我之前就让它动态导入,确保只在客户端渲染(封装的服务器组件本身会先渲染,组件里的子级组件才会被延迟加载),现在居然报了服务端组件不能使用 ssr:false
⨯ ./app/page.tsx
Error: × ssr: false is not allowed with next/dynamic in Server Components. Please move it into a client component.
╭─[/Users/tangyusen/Project/nextProject/blog/app/page.tsx:6:1]
4 │ import dynamic from "next/dynamic"
5 │
6 │ const R3FBox = dynamic(() => import('@/components/model/R3FBox'), { ssr: false })
查了文档,发现多出来了一个要求 ssr 为 false 只能在客户端组件使用,那就去掉 ssr 的字段,查看控制台发现 page.js 的 size 增加了 2M,先放着吧,后续再优化了,先把升级搞完。再次运行,还是继续报错
TypeError: Cannot read properties of undefined (reading 'ReactCurrentOwner')
查了一下挺多库都会导致这个报错,换了几个搜索答案,看到了有人用 three/fiber 报这个错,我就吧 R3FBox 的组件先注释了,成功展示页面。确定了是 three/fiber 引起的,那接下来就去社区找找看怎么解决,在一个 issues 问题里找到了答案,一同将 three/fiber 库升级到 alpha 版本,运行下来就没有问题了。
进入页面后报了另一个错误,是路由拿参数报错的,Next.js 的最新版本中,动态路由的 params 需要通过 await 来处理,因为它们是异步获取的。报错提示的是,你需要先 await params,才能使用获取到参数
Route "/posts/[slug]" used `params.slug`. `params` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
at slug (webpack:///app/posts/[slug]/page.tsx?71c2:26:27)
24 |
25 | export default function PostPage(props: any) {
> 26 | const slug = props.params.slug
修改为下面的内容即可
export default async function PostPage(props: any) {
const { slug } = await props.params;
}