vibcoding Team5 分で読めます
Next.js 15 性能优化实战:从 5s 到 1s 的加载提升
深入分析 Next.js 15 性能优化策略,包括 Server Components、Streaming、缓存策略和代码分割,附真实优化案例。
#Next.js#性能优化#React#Web开发#前端
Next.js 15 性能优化实战:从 5s 到 1s 的加载提升
问题背景
我们的 AI 工具网站使用 Next.js 15 构建,上线后发现首屏加载时间高达 5.5 秒,用户体验极差。
Speed Insights 诊断结果:
- TTFB: 5.5s ❌
- FCP: 6.68s ❌
- LCP: 6.68s ❌
- Real Experience Score: 37 ❌
经过一系列优化后:
- TTFB: 0.8s ✅
- FCP: 1.2s ✅
- LCP: 1.5s ✅
- Real Experience Score: 92 ✅
下面分享完整的优化过程。
第一步:分析问题根源
使用浏览器 DevTools Network 面板发现:
- 页面加载时发起 20+ 个 API 请求
- 巨大的 JavaScript bundle (2.5MB)
- 未优化的图片 (每张 500KB+)
- 大量 307 重定向
第二步:优化 Server Components
之前(问题代码)
tsx
// ❌ 在客户端组件中获取数据
'use client';
export default function Dashboard() {
const [data, setData] = useState(null);
useEffect(() => {
// 这会导致客户端请求,增加 TTFB
fetch('/api/stats').then(r => r.json()).then(setData);
}, []);
return <div>{data ? <Stats data={data} /> : <Loading />}</div>;
}
之后(优化后)
tsx
// ✅ 使用 Server Component 直接获取数据
async function Dashboard() {
// 数据在服务端获取,直接渲染 HTML
const data = await fetchStats();
return <Stats data={data} />;
}
// 交互组件单独抽离
'use client';
function InteractiveChart({ data }) {
// 只有需要交互的部分才是客户端组件
return <Chart data={data} onClick={...} />;
}
效果: TTFB 从 5.5s 降到 1.2s
第三步:实现 Streaming
tsx
// app/dashboard/page.tsx
import { Suspense } from 'react';
export default function DashboardPage() {
return (
<div>
{/* 立即显示的静态内容 */}
<Header />
{/* 慢数据使用 Suspense 包裹 */}
<Suspense fallback={<StatsSkeleton />}>
<Stats />
</Suspense>
<Suspense fallback={<ChartSkeleton />}>
<Charts />
</Suspense>
<Suspense fallback={<TableSkeleton />}>
<RecentActivity />
</Suspense>
</div>
);
}
效果: FCP 从 6.68s 降到 1.5s(骨架屏立即显示)
第四步:优化代码分割
动态导入重型组件
tsx
import dynamic from 'next/dynamic';
// 重型图表库延迟加载
const HeavyChart = dynamic(
() => import('@/components/HeavyChart'),
{
loading: () => <ChartSkeleton />,
ssr: false
}
);
// Monaco 编辑器延迟加载
const CodeEditor = dynamic(
() => import('@monaco-editor/react'),
{
loading: () => <div className="h-96 bg-gray-100 animate-pulse" />,
ssr: false
}
);
next.config.mjs 优化
javascript
export default {
experimental: {
optimizePackageImports: [
'@radix-ui/react-icons',
'framer-motion',
'lucide-react',
],
},
// 生产环境移除 console.log
compiler: {
removeConsole: process.env.NODE_ENV === 'production'
? { exclude: ['error', 'warn'] }
: false,
},
};
效果: JS Bundle 从 2.5MB 降到 800KB
第五步:禁用不必要的预取
tsx
// 导航链接禁用预取
<Link href="/dashboard" prefetch={false}>
Dashboard
</Link>
// 或者在 next.config.mjs 全局配置
experimental: {
// 只在 hover 时预取
linkPrefetch: 'intent',
}
效果: 减少 80% 的不必要请求
第六步:图片优化
tsx
import Image from 'next/image';
// ✅ 使用 next/image 自动优化
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={630}
priority // 首屏图片使用 priority
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
/>
next.config.mjs 图片配置
javascript
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920],
minimumCacheTTL: 31536000, // 1年缓存
},
效果: 图片体积减少 70%
第七步:缓存策略
页面级缓存
tsx
// 静态页面启用 ISR
export const revalidate = 3600; // 1小时重新验证
// 动态页面使用 unstable_cache
import { unstable_cache } from 'next/cache';
const getCachedStats = unstable_cache(
async () => {
return await db.query('SELECT ...');
},
['stats'],
{ revalidate: 60 }
);
HTTP 缓存头
javascript
// next.config.mjs
async headers() {
return [
{
source: '/_next/static/:path*',
headers: [
{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' },
],
},
];
}
最终成果
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| TTFB | 5.5s | 0.8s | 85% |
| FCP | 6.68s | 1.2s | 82% |
| LCP | 6.68s | 1.5s | 78% |
| JS Bundle | 2.5MB | 800KB | 68% |
| Score | 37 | 92 | 149% |
检查清单
- Server Components 处理数据获取
- Suspense 包裹慢组件
- 动态导入重型组件
- 禁用不必要的 Link prefetch
- 使用 next/image 优化图片
- 配置适当的缓存策略
- 移除生产环境的 console.log
总结
Next.js 15 提供了强大的性能优化工具,但需要正确使用:
- Server Components First - 尽可能在服务端处理数据
- Progressive Loading - 使用 Suspense 实现渐进式加载
- Lazy Everything - 非首屏内容全部延迟加载
- Cache Aggressively - 能缓存的都缓存
性能优化是持续的过程,建议定期使用 Vercel Speed Insights 或 Lighthouse 监控。
更多优化技巧欢迎在 GitHub 讨论!
v
vibcoding Team
vibcoding Tech Team