Next.js 14 新特性实战体验:App Router 到底好不好用
迁移背景:为什么从Pages Router转到App Router
2026年2月,我决定将Harukaze Lab个人网站从Next.js Pages Router迁移到App Router。这不是一次简单的框架升级,而是开发思维的根本性转变。
迁移前的痛点:
- LCP 4.2秒(首屏加载太慢)
- Bundle Size 245KB(客户端JS太大)
- Lighthouse评分只有62(不及格)
核心变化:Server Components默认模式
最大的改变:所有组件默认都是Server Components,只有明确标记"use client"的才是Client Components。
数据获取方式的革命
// ❌ 旧方式(Pages Router + useEffect)
function ArticleList() {
const [articles, setArticles] = useState([])
useEffect(() => {
fetch('/api/articles')
.then(res => res.json())
.then(data => setArticles(data))
}, [])
return articles.map(article => )
}
// ✅ 新方式(App Router + Server Component)
async function ArticleList() {
const articles = await db.query('SELECT * FROM articles')
return articles.map(article => )
}
效果:代码量减少40%,客户端JS减少62%。
性能优化成果
| 指标 | 优化前 | 优化后 | 提升幅度 |
|---|---|---|---|
| LCP(首屏内容绘制) | 4.2s | 1.1s | ⬆️ 74% |
| Bundle Size | 245KB | 87KB | ⬇️ 64% |
| Lighthouse评分 | 62 | 95 | ⬆️ 53% |
| FID(首次输入延迟) | 180ms | 45ms | ⬆️ 75% |
具体优化技术
1)图片优化 next/image
- WebP自动转换+懒加载+Blur placeholder
- 体积减少60%
2)代码分割 React.lazy()
- 动态导入非首屏组件
- @next/bundle-analyzer分析大文件
3)缓存策略 ISR + SWR
export const revalidate = 60 // ISR:每60秒增量静态再生成
4)CSS优化 Tailwind PurgeCSS
- 移除80%未使用样式
- Critical CSS内联
App Router最佳实践
Server Components用于:
- ✅ 数据获取和数据库查询
- ✅ 访问后端资源和敏感信息
- ✅ 直接操作文件系统
- ✅ 减少客户端JavaScript
Client Components仅在需要时使用:
- ❗ useState / useEffect等React Hooks
- ❗ 浏览器事件处理(onClick/onChange)
- ❗ 浏览器API(localStorage/geolocation)
- ❗ 需要实时交互的UI组件
常见坑及解决方案
坑1:过度使用"use client"
症状:几乎所有组件都加了"use client",性能没有改善甚至下降。
解决方案:默认Server Components,只在真正需要时添加"use client"。
坑2:Client Components中fetch数据
症状:出现Waterfall请求(串行请求导致加载慢)。
解决方案:数据获取提升到Server Components或使用Server Actions。
坑3:第三方脚本阻塞渲染
症状:LCP和FID指标变差。
解决方案:
import Script from 'next/script'
<Script
src="https://example.com/third-party.js"
strategy="lazyOnload"
onLoad={() => console.log('Script loaded')}
/>
Server Actions实战
替代传统API路由的新方式:
// app/actions.ts
'use server'
import { z } from 'zod'
import { revalidatePath } from 'next/cache'
const contactSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
message: z.string().min(10)
})
export async function submitContact(formData: FormData) {
const validated = contactSchema.parse({
name: formData.get('name'),
email: formData.get('email'),
message: formData.get('message')
})
await db.contacts.create({ data: validated })
revalidatePath('/contact') // 自动刷新缓存
return { success: true }
}
Streaming SSR + Suspense实践
import { Suspense } from 'react'
function LoadingSkeleton() {
return <div className="animate-pulse">Loading...</div>
}
export default function Page() {
return (
<div>
<Suspense fallback={<LoadingSkeleton />}>
<SlowComponent /> // 这个组件会流式加载
</Suspense>
<FastComponent /> // 这个组件立即显示
</div>
)
}
效果:TTV(Time To View)降低40%,用户体验显著提升。
监控体系
- Vercel Analytics:实时性能监控和用户行为分析
- Sentry错误追踪:捕获并追踪生产环境错误
- Lighthouse CI:每次部署自动运行性能测试
本文基于作者2026年2-3月的真实项目迁移经验整理。最后更新于2026年3月25日。