乐闻世界logo
搜索文章和话题

如何优化 Vercel 应用的性能?

2月21日 16:28

如何优化 Vercel 应用的性能?

优化 Vercel 应用的性能是一个多方面的任务,涉及前端构建、资源加载、服务器端渲染、缓存策略等多个层面。以下是从不同角度优化 Vercel 应用性能的详细指南。

构建优化

1. 代码分割

自动代码分割

Next.js 和现代前端框架会自动进行代码分割,但你可以进一步优化:

javascript
// 动态导入组件 const HeavyComponent = dynamic(() => import('./HeavyComponent'), { loading: () => <LoadingSpinner />, ssr: false // 禁用服务端渲染 }); export default function Page() { return <HeavyComponent />; }

路由级别的分割

  • 每个路由自动分割成独立的 chunk
  • 只加载当前路由需要的代码
  • 利用 Next.js 的自动分割

2. Tree Shaking

移除未使用的代码

javascript
// 避免导入整个库 // ❌ 不好 import _ from 'lodash'; // ✅ 好 import { debounce } from 'lodash';

使用 ES Modules

  • 确保使用 ES Module 语法
  • 配置 package.json 的 "type": "module"
  • 使用支持 tree shaking 的库

3. 依赖优化

分析包大小

bash
# 使用 webpack-bundle-analyzer npm install --save-dev @next/bundle-analyzer
javascript
// next.config.js const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }); module.exports = withBundleAnalyzer({ // 其他配置 });

优化策略

  • 移除不必要的依赖
  • 使用更轻量的替代库
  • 按需导入大型库

资源加载优化

1. 图片优化

使用 next/image

jsx
import Image from 'next/image'; export default function Hero() { return ( <Image src="/hero.jpg" alt="Hero section" width={800} height={600} priority // 首屏图片 placeholder="blur" // 模糊占位符 /> ); }

优化技巧

  • 使用 WebP、AVIF 等现代格式
  • 提供正确的尺寸
  • 使用 priority 属性加载首屏图片
  • 使用 placeholder 提升用户体验

2. 字体优化

使用 next/font

jsx
import { Inter } from 'next/font/google'; const inter = Inter({ subsets: ['latin'], display: 'swap', variable: '--font-inter', }); export default function RootLayout({ children }) { return ( <html className={inter.variable}> <body>{children}</body> </html> ); }

优化策略

  • 只加载需要的字符集
  • 使用 display: swap 避免布局偏移
  • 使用 CSS 变量应用字体

3. CSS 优化

CSS-in-JS 优化

jsx
// 使用 styled-components import styled from 'styled-components'; const Button = styled.button` background: ${props => props.theme.primary}; color: white; padding: 10px 20px; `;

CSS Modules

  • 自动提取和压缩 CSS
  • 避免样式冲突
  • 更好的缓存策略

渲染策略优化

1. 静态生成(SSG)

使用 getStaticProps

javascript
export async function getStaticProps() { const posts = await getPosts(); return { props: { posts }, revalidate: 3600, // ISR:每小时重新生成 }; }

优势

  • 预渲染 HTML
  • CDN 缓存
  • 极快的加载速度
  • 更好的 SEO

2. 增量静态再生成(ISR)

按需重新验证

javascript
export async function getStaticPaths() { const posts = await getPosts(); return { paths: posts.map(post => ({ params: { id: post.id } })), fallback: 'blocking' }; } export async function getStaticProps({ params }) { const post = await getPost(params.id); return { props: { post }, revalidate: 60, // 60 秒后可以重新生成 }; } // API 路由用于手动重新验证 // pages/api/revalidate.js export default async function handler(req, res) { const { id } = req.query; await res.revalidate(`/posts/${id}`); res.json({ revalidated: true }); }

3. 服务端渲染(SSR)

选择性使用 SSR

javascript
// 只对需要实时数据的页面使用 SSR export async function getServerSideProps() { const data = await fetchRealTimeData(); return { props: { data } }; }

优化策略

  • 只在必要时使用 SSR
  • 缓存 API 响应
  • 使用 Streaming 减少首屏时间

缓存策略

1. CDN 缓存

配置缓存头

javascript
// vercel.json { "headers": [ { "source": "/static/:path*", "headers": [ { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" } ] } ] }

缓存策略

  • 静态资源:长期缓存
  • API 响应:短期缓存
  • HTML:根据内容变化

2. 数据缓存

使用 Vercel KV

javascript
import { kv } from '@vercel/kv'; export async function getPosts() { const cached = await kv.get('posts'); if (cached) { return JSON.parse(cached); } const posts = await fetchPosts(); await kv.set('posts', JSON.stringify(posts), { ex: 3600 }); return posts; }

3. 客户端缓存

使用 SWR

javascript
import useSWR from 'swr'; const fetcher = url => fetch(url).then(r => r.json()); function Posts() { const { data, error } = useSWR('/api/posts', fetcher, { revalidateOnFocus: false, revalidateOnReconnect: false, dedupingInterval: 60000 }); if (error) return <div>Error</div>; if (!data) return <div>Loading...</div>; return <PostsList posts={data} />; }

网络优化

1. HTTP/2 和 HTTP/3

Vercel 自动支持 HTTP/2 和 HTTP/3,无需额外配置。

优势

  • 多路复用
  • 头部压缩
  • 服务器推送
  • 更快的连接建立

2. 预加载和预连接

预加载关键资源

jsx
export default function Document() { return ( <Html> <Head> <link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossOrigin="" /> <link rel="preconnect" href="https://api.example.com" /> </Head> <body /> </Html> ); }

3. 减少请求

合并请求

  • 使用 GraphQL 减少请求次数
  • 批量 API 调用
  • 使用请求合并中间件

性能监控

1. Vercel Analytics

集成 Analytics

jsx
import { Analytics } from '@vercel/analytics/react'; export default function RootLayout({ children }) { return ( <html> <body> {children} <Analytics /> </body> </html> ); }

监控指标

  • Web Vitals(LCP、FID、CLS)
  • 页面加载时间
  • 用户行为分析

2. 自定义监控

性能追踪

javascript
export async function getServerSideProps() { const start = Date.now(); const data = await fetchData(); const duration = Date.now() - start; // 发送到监控服务 await logMetric('data_fetch_duration', duration); return { props: { data } }; }

Edge Runtime 优化

1. 使用 Edge Runtime

配置 Edge Runtime

javascript
export const runtime = 'edge'; export default function handler(request) { return new Response('Hello from Edge!'); }

优势

  • 更快的冷启动
  • 更低的延迟
  • 全球边缘执行
  • 更好的性能

2. Edge Middleware

使用 Middleware

javascript
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export function middleware(request: NextRequest) { // 在边缘执行,减少延迟 const response = NextResponse.next(); // 添加自定义头 response.headers.set('X-Custom-Header', 'value'); return response; } export const config = { matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'], };

数据库优化

1. 连接池

重用数据库连接

javascript
import { PrismaClient } from '@prisma/client'; const globalForPrisma = global as unknown as { prisma: PrismaClient }; export const prisma = globalForPrisma.prisma || new PrismaClient(); if (process.env.NODE_ENV !== 'production') { globalForPrisma.prisma = prisma; }

2. 查询优化

优化数据库查询

javascript
// 只选择需要的字段 const users = await prisma.user.findMany({ select: { id: true, name: true, email: true } }); // 使用索引 const user = await prisma.user.findUnique({ where: { email: userEmail } }); // 分页 const users = await prisma.user.findMany({ skip: 0, take: 10 });

构建配置优化

1. Next.js 配置

优化 next.config.js

javascript
/** @type {import('next').NextConfig} */ const nextConfig = { // 启用压缩 compress: true, // 优化图片 images: { formats: ['image/avif', 'image/webp'], deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], }, // 实验性功能 experimental: { optimizeCss: true, }, // 生产环境优化 productionBrowserSourceMaps: false, // 减少输出大小 swcMinify: true, }; module.exports = nextConfig;

2. Webpack 配置

自定义 webpack 配置

javascript
module.exports = { webpack: (config, { isServer }) => { // 优化打包 config.optimization = { ...config.optimization, splitChunks: { chunks: 'all', cacheGroups: { default: false, vendors: false, vendor: { name: 'vendor', chunks: 'all', test: /node_modules/, priority: 20 }, common: { name: 'common', minChunks: 2, chunks: 'all', priority: 10, reuseExistingChunk: true, enforce: true } } } }; return config; } };

部署优化

1. 区域选择

选择最近的区域

json
{ "regions": ["iad1"] }

可用区域

  • iad1:美国东部
  • hkg1:香港
  • sin1:新加坡
  • 等等

2. 构建缓存

利用 Vercel 缓存

  • Vercel 自动缓存 node_modules
  • 缓存构建产物
  • 使用增量构建

最佳实践总结

1. 监控和分析

  • 使用 Vercel Analytics 监控性能
  • 定期检查 Web Vitals
  • 分析用户行为数据
  • 识别性能瓶颈

2. 持续优化

  • 定期审查依赖
  • 优化图片和字体
  • 改进缓存策略
  • 测试不同渲染策略

3. 性能预算

  • 设置性能预算
  • 监控包大小
  • 限制资源加载时间
  • 定期进行性能审计

4. 测试和验证

  • 使用 Lighthouse 进行性能测试
  • 在不同网络条件下测试
  • 监控真实用户数据(RUM)
  • 进行 A/B 测试

常见性能问题及解决方案

1. 首屏加载慢

解决方案

  • 使用 SSG 或 ISR
  • 优化关键渲染路径
  • 预加载关键资源
  • 使用 Skeleton 加载状态

2. 交互延迟高

解决方案

  • 减少主线程工作
  • 使用 Web Workers
  • 优化 JavaScript 执行
  • 使用防抖和节流

3. 内存占用高

解决方案

  • 优化数据加载
  • 使用虚拟列表
  • 及时清理不再使用的资源
  • 避免内存泄漏

通过以上优化策略,可以显著提升 Vercel 应用的性能,提供更好的用户体验。记住,性能优化是一个持续的过程,需要不断地监控、分析和改进。

标签:Vercel