性能优化 #
性能优化概述 #
Vercel 提供多层次的性能优化:
text
┌─────────────────────────────────────────┐
│ 性能优化层次 │
├─────────────────────────────────────────┤
│ 边缘层 → CDN 缓存、边缘函数 │
│ 构建层 → 代码分割、资源优化 │
│ 运行时层 → 服务端渲染、流式传输 │
│ 客户端层 → 懒加载、预加载 │
└─────────────────────────────────────────┘
缓存策略 #
静态资源缓存 #
json
{
"headers": [
{
"source": "/static/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
},
{
"source": "/(.*).js",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
},
{
"source": "/(.*).css",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
}
]
}
API 缓存 #
typescript
import { NextResponse } from 'next/server'
export async function GET() {
const data = await fetchData()
return NextResponse.json(data, {
headers: {
'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=300',
},
})
}
缓存指令说明 #
text
Cache-Control 值:
├── public → 可被任何缓存存储
├── private → 仅浏览器缓存
├── max-age=3600 → 缓存 1 小时
├── s-maxage=3600 → CDN 缓存 1 小时
├── stale-while-revalidate=60 → 过期后 60 秒内可使用旧响应
├── immutable → 永不过期
└── no-cache → 每次验证
边缘缓存 #
ISR(增量静态再生) #
typescript
export const revalidate = 60
export default async function Page() {
const data = await fetch('https://api.example.com/data', {
next: { revalidate: 60 }
}).then(res => res.json())
return <div>{data.title}</div>
}
按需重新验证 #
typescript
import { revalidatePath, revalidateTag } from 'next/cache'
import { NextRequest, NextResponse } from 'next/server'
export async function POST(request: NextRequest) {
const path = request.nextUrl.searchParams.get('path')
if (path) {
revalidatePath(path)
return NextResponse.json({ revalidated: true, now: Date.now() })
}
revalidateTag('collection')
return NextResponse.json({ revalidated: true, now: Date.now() })
}
缓存标签 #
typescript
export default async function Page() {
const data = await fetch('https://api.example.com/data', {
next: { tags: ['collection'] }
}).then(res => res.json())
return <div>{data.title}</div>
}
构建优化 #
代码分割 #
typescript
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('@/components/Heavy'), {
loading: () => <p>Loading...</p>,
ssr: false,
})
export default function Page() {
return (
<div>
<DynamicComponent />
</div>
)
}
Tree Shaking #
javascript
import { debounce, throttle } from 'lodash-es'
import { format } from 'date-fns'
包体积分析 #
bash
npm install @next/bundle-analyzer
javascript
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
module.exports = withBundleAnalyzer({
// next config
})
bash
ANALYZE=true npm run build
外部依赖优化 #
javascript
module.exports = {
experimental: {
optimizePackageImports: ['lodash', 'date-fns', '@mui/material'],
},
}
运行时优化 #
流式渲染 #
typescript
import { Suspense } from 'react'
async function SlowComponent() {
const data = await fetch('https://api.example.com/slow')
return <div>{data}</div>
}
export default function Page() {
return (
<div>
<h1>Fast Content</h1>
<Suspense fallback={<p>Loading...</p>}>
<SlowComponent />
</Suspense>
</div>
)
}
并行数据获取 #
typescript
async function Page() {
const [users, posts, comments] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json()),
])
return (
<div>
<UsersList users={users} />
<PostsList posts={posts} />
<CommentsList comments={comments} />
</div>
)
}
预加载资源 #
tsx
import Link from 'next/link'
export default function Page() {
return (
<div>
<Link href="/about" prefetch>
About
</Link>
</div>
)
}
图片优化 #
tsx
import Image from 'next/image'
export default function Page() {
return (
<>
<Image
src="/hero.jpg"
alt="Hero"
width={800}
height={600}
priority
/>
<Image
src="/gallery/1.jpg"
alt="Gallery"
width={400}
height={300}
loading="lazy"
/>
</>
)
}
字体优化 #
tsx
import { Inter } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap',
})
export default function Layout({ children }) {
return (
<html lang="en" className={inter.className}>
<body>{children}</body>
</html>
)
}
客户端优化 #
懒加载组件 #
tsx
import { lazy, Suspense } from 'react'
const HeavyComponent = lazy(() => import('./Heavy'))
export default function Page() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
)
}
虚拟列表 #
bash
npm install react-window
tsx
import { FixedSizeList } from 'react-window'
const Row = ({ index, style }) => (
<div style={style}>Item {index}</div>
)
export default function VirtualList({ items }) {
return (
<FixedSizeList
height={400}
itemCount={items.length}
itemSize={35}
width="100%"
>
{Row}
</FixedSizeList>
)
}
Service Worker #
javascript
public/sw.js
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request)
})
)
})
数据库优化 #
连接池 #
typescript
import { Pool } from 'pg'
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 1,
})
export async function query(text: string, params?: any[]) {
const client = await pool.connect()
try {
return await client.query(text, params)
} finally {
client.release()
}
}
查询优化 #
typescript
import { prisma } from '@/lib/prisma'
export async function getUsers() {
return prisma.user.findMany({
select: {
id: true,
name: true,
email: true,
},
where: {
active: true,
},
take: 20,
})
}
性能预算 #
配置性能预算 #
json
{
"budgets": [
{
"resourceType": "script",
"budget": 300
},
{
"resourceType": "stylesheet",
"budget": 100
},
{
"resourceType": "image",
"budget": 500
},
{
"resourceType": "total",
"budget": 1000
}
]
}
Lighthouse CI #
yaml
.github/workflows/lighthouse.yml
name: Lighthouse CI
on: [push]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: treosh/lighthouse-ci-action@v10
with:
urls: |
https://your-site.vercel.app
budgetPath: ./budget.json
性能监控 #
Web Vitals 监控 #
typescript
import { useReportWebVitals } from 'next/web-vitals'
export function WebVitals() {
useReportWebVitals((metric) => {
if (metric.name === 'LCP' && metric.value > 2500) {
console.warn('LCP is slow:', metric.value)
}
})
}
性能标记 #
typescript
export default function Page() {
performance.mark('page-start')
// ... 组件代码
performance.mark('page-end')
performance.measure('page-render', 'page-start', 'page-end')
return <div>Content</div>
}
最佳实践 #
性能优化清单 #
text
┌─────────────────────────────────────────┐
│ 性能优化清单 │
├─────────────────────────────────────────┤
│ ✓ 启用静态资源缓存 │
│ ✓ 使用 ISR 减少服务器负载 │
│ ✓ 代码分割减少包体积 │
│ ✓ 图片自动优化 │
│ ✓ 字体预加载 │
│ ✓ 使用流式渲染 │
│ ✓ 并行数据获取 │
│ ✓ 设置性能预算 │
│ ✓ 监控 Web Vitals │
└─────────────────────────────────────────┘
Core Web Vitals 目标 #
text
LCP < 2.5s
FID < 100ms
CLS < 0.1
INP < 200ms
TTFB < 600ms
下一步 #
了解性能优化后,接下来学习 故障排查 掌握问题排查技巧!
最后更新:2026-03-28