Next.js 15 优化技能
目标
优化 Next.js 应用程序以实现:
- 完美的核心 Web 指标得分(LCP < 2.5s, FID < 100ms, CLS < 0.1)
- 快速的页面加载时间和最优的渲染策略
- 高效的数据获取和缓存
- 生产就绪的构建配置
- SEO 和无障碍卓越
何时使用此技能
自动调用时:
- 项目使用 Next.js(通过
next在依赖项中检测) - 用户提到“优化”,“性能”,“慢”或“核心 Web 指标”
- 生产部署前
- 添加新功能或页面后
- 用户请求 Next.js 特定的改进
先决条件检查
工具:读取,搜索
-
验证 Next.js 版本:
# 读取 package.json # 检查 "next": "^15.0.0" 或更高版本 -
检测 App Router(Next.js 13+):
- 检查
app/目录 - 检查
layout.tsx,page.tsx文件
- 检查
-
检测页面路由器(遗留):
- 检查
pages/目录 - 建议迁移到 App Router
- 检查
优化类别
1. 渲染策略优化
目标:为每个页面/组件选择最优的渲染
工具:读取,搜索,编辑
1.1 服务器组件(App Router 默认)
何时使用:
- 从 API/数据库获取数据
- 重计算
- 访问后端资源
模式:
// app/dashboard/page.tsx
export default async function DashboardPage() {
const data = await fetchData(); // 在服务器上运行
return <Dashboard data={data} />;
}
检查违规:
# 在不需要的组件中搜索 "use client"
grep -r "use client" app/ | grep -v "onClick\|useState\|useEffect"
1.2 客户端组件
何时使用:
- 交互式 UI(onClick, 表单)
- 浏览器 API(window, localStorage)
- React 钩子(useState, useEffect)
模式:
// app/components/Counter.tsx
'use client';
export default function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
优化:保持客户端组件小而叶节点
1.3 静态生成(SSG)
何时使用:
- 很少变化的内容
- 营销页面,博客,文档
模式:
export const revalidate = 3600; // 每小时重新验证一次
export default async function BlogPost({ params }) {
const post = await getPost(params.slug);
return <Article post={post} />;
}
1.4 动态渲染与 ISR
何时使用:
- 定期变化的内容
- 电子商务产品,用户配置文件
模式:
export const revalidate = 60; // 每分钟重新验证一次
export async function generateStaticParams() {
const products = await getProducts();
return products.map((p) => ({ slug: p.slug }));
}
2. 图像优化
目标:优化图像以提高性能和核心 Web 指标
工具:搜索,读取,编辑
2.1 使用 Next.js 图像组件
查找未优化的图像:
grep -rn "<img " app/ src/
替换为:
import Image from 'next/image';
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={600}
priority // 对于页面上方的图像
placeholder="blur" // 可选的模糊效果
/>
2.2 配置图像域
读取 next.config.js:
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
],
formats: ['image/avif', 'image/webp'], // 现代格式
},
};
2.3 延迟加载策略
- priority:页面上方的图像(LCP 候选)
- loading=“lazy”:页面下方的图像(默认)
3. 字体优化
目标:消除 FOUT/FOIT 并改善字体加载
工具:读取,编辑
3.1 使用 next/font
模式:
// app/layout.tsx
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap', // 防止 FOIT
variable: '--font-inter',
});
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.variable}>
<body>{children}</body>
</html>
);
}
3.2 自托管字体
import localFont from 'next/font/local';
const customFont = localFont({
src: './fonts/CustomFont.woff2',
display: 'swap',
variable: '--font-custom',
});
4. 数据获取优化
目标:最小化瀑布流并优化缓存
工具:读取,搜索,编辑
4.1 并行数据获取
反模式(顺序):
const user = await getUser();
const posts = await getPosts(user.id); // 等待用户
优化(并行):
const [user, posts] = await Promise.all([
getUser(),
getPosts(),
]);
4.2 流式传输与 Suspense
模式:
import { Suspense } from 'react';
export default function Page() {
return (
<>
<Header />
<Suspense fallback={<Skeleton />}>
<SlowComponent />
</Suspense>
<Footer />
</>
);
}
4.3 缓存配置
// 积极缓存
fetch('https://api.example.com/data', {
next: { revalidate: 3600 }, // 缓存 1 小时
});
// 无缓存
fetch('https://api.example.com/data', {
cache: 'no-store', // 总是新鲜的
});
// 退出缓存
export const dynamic = 'force-dynamic';
5. 捆绑优化
目标:减少 JavaScript 捆绑包大小
工具:Bash,读取,编辑
5.1 分析捆绑包
# 添加到 package.json 脚本
npm run build
npx @next/bundle-analyzer
5.2 动态导入
查找大组件:
find app -name "*.tsx" -exec wc -l {} \; | sort -rn | head -10
用动态导入拆分:
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <Skeleton />,
ssr: false, // 如果不需要则跳过 SSR
});
5.3 树摇动
检查桶导出:
grep -rn "export \* from" app/
替换为特定导入:
// 反模式
import { Button, Card, Modal } from '@/components';
// 优化
import { Button } from '@/components/Button';
6. 元数据和 SEO
目标:完美的 SEO 和社交分享
工具:读取,编辑
6.1 静态元数据
// app/layout.tsx
export const metadata = {
title: {
default: 'My App',
template: '%s | My App',
},
description: 'Description for SEO',
openGraph: {
title: 'My App',
description: 'Description for social sharing',
images: ['/og-image.jpg'],
},
twitter: {
card: 'summary_large_image',
},
};
6.2 动态元数据
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
images: [post.ogImage],
},
};
}
7. 生产配置
目标:为生产优化 next.config.js
工具:读取,编辑
7.1 基本配置
// next.config.js
module.exports = {
reactStrictMode: true,
poweredByHeader: false, // 安全
compress: true, // Gzip 压缩
// 编译器优化
compiler: {
removeConsole: process.env.NODE_ENV === 'production',
},
// 图像优化
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920],
},
// React 编译器(Next.js 15)
experimental: {
reactCompiler: true,
},
};
7.2 Turbopack(开发)
// package.json
{
"scripts": {
"dev": "next dev --turbo"
}
}
8. 核心 Web 指标优化
目标:实现完美的 Lighthouse 得分
工具:Bash,搜索,编辑
8.1 LCP(最大内容绘制)< 2.5s
优化:
- 使用
priority对英雄图像 - 预加载关键资源
- 服务器端渲染页面上方的内容
// 预加载关键资源
<link rel="preload" href="/hero.jpg" as="image" />
8.2 FID(首次输入延迟)< 100ms
优化:
- 最小化 JavaScript 执行
- 为非关键代码使用动态导入
- 延迟第三方脚本
import Script from 'next/script';
<Script
src="https://analytics.example.com"
strategy="lazyOnload" // 页面交互后加载
/>
8.3 CLS(累积布局偏移)< 0.1
优化:
- 始终指定图像尺寸
- 为动态内容预留空间
- 使用
font-display: swap
/* 为广告/横幅预留空间 */
.ad-container {
min-height: 250px;
}
9. 缓存策略
目标:最大化缓存命中并最小化服务器负载
工具:读取,编辑
9.1 路由段配置
// app/dashboard/page.tsx
export const revalidate = 3600; // ISR 每小时
export const dynamic = 'auto'; // 自动优化
export const fetchCache = 'force-cache'; // 积极缓存
9.2 数据缓存
// 自动去重和缓存
const user = await fetch('https://api.example.com/user');
// 基于标签重新验证
export const revalidate = 60;
export const tags = ['user', 'profile'];
10. 监控和测量
目标:随时间跟踪性能
工具:Bash,网络搜索
10.1 添加 Web 指标报告
// app/layout.tsx
import { SpeedInsights } from '@vercel/speed-insights/next';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<SpeedInsights />
</body>
</html>
);
}
10.2 Lighthouse CI
# 运行 Lighthouse
npx lighthouse http://localhost:3000 --view
# 检查核心 Web 指标
npm run build
npm run start
npx lighthouse http://localhost:3000 --only-categories=performance
优化清单
运行此清单:
- [ ] 所有图像使用
next/image并具有适当的尺寸 - [ ] 字体使用
next/font并具有display: swap - [ ] 默认使用服务器组件(无不必要的 ‘use client’)
- [ ] 客户端组件是叶节点且最小化
- [ ] 数据获取尽可能使用并行请求
- [ ] 慢速组件用
<Suspense>包装 - [ ] 大型组件使用动态导入
- [ ] 为所有页面配置元数据
- [ ]
next.config.js具有生产优化 - [ ] 启用 React 编译器(Next.js 15)
- [ ] 分析并优化捆绑包
- [ ] 核心 Web 指标达到目标(使用 Lighthouse 测试)
输出格式
# Next.js 优化报告
## 当前状态
- **Next.js 版本**:15.0.3
- **渲染**:App Router
- **React 版本**:19.0.0
## 发现的问题
### 🔴 严重(3)
1. **未优化的图像**:发现 12 个 `<img>` 标签
- 文件:`app/page.tsx`, `app/about/page.tsx`
- 修复:替换为 `next/image`
2. **大型客户端捆绑包**:342 KB(目标:< 200 KB)
- 原因:同步加载重型图表库
- 修复:对 `Chart` 组件使用动态导入
3. **缺少字体优化**:通过 <link> 使用 Google 字体
- 修复:迁移到 `next/font/google`
### 🟡 警告(2)
1. **顺序数据获取**:在 `app/dashboard/page.tsx` 中检测到瀑布流
2. **无元数据**:5 个页面缺少 OpenGraph 标签
## 应用的优化
✅ 在 next.config.js 中启用 React 编译器
✅ 添加图像优化配置
✅ 配置适当的缓存头
✅ 向慢速路由添加 Suspense 边界
## 性能影响(估计)
- **加载时间**:3.2s → 1.8s(-44%)
- **捆绑包大小**:342 KB → 198 KB(-42%)
- **LCP**:3.1s → 2.3s(✅ 良好)
- **FID**:85ms → 45ms(✅ 良好)
- **CLS**:0.15 → 0.05(✅ 良好)
## 下一步
1. 替换 12 个 `<img>` 标签为 `next/image`
2. 使用动态导入拆分图表组件
3. 为 5 个页面添加元数据
4. 运行 Lighthouse 以验证改进