Next.js 性能优化:从 50 分到 99 分的调优指南
在如今的 Web 开发中,“快”不仅仅是用户体验,更是 SEO 排名和转化率的生命线。很多开发者做出来的 Next.js 网站,功能很强,UI 很炫,但一跑 Lighthouse 惨不忍睹,甚至在低端设备上卡顿明显。
尤其是 LCP (最大内容绘制) 和 CLS (累积布局偏移),往往是 Next.js 应用的重灾区。
今天我们不聊虚的理论,不背 HTTP 缓存协议。直接针对 Next.js 框架特性,给出一套实战优化组合拳,看看如何把一个 50 分的网站优化到 90+。
1. LCP 杀手:极致的图片加载策略
LCP 衡量视口中最大内容的渲染时间。对于大多数电商或博客网站,这通常是首屏的 Hero Banner 或主商品图。
❌ 常见误区
- 盲目懒加载:给首屏大图加
loading="lazy"。这听起来是优化,实则是大错特错。浏览器会等到确定图片在视口内才开始加载,这不会节省带宽,只会浪费宝贵的并发下载时间。 - 使用普通
<img>标签:没有SRCSET,导致移动端下载了 4K 分辨率的 PC 端大图。
✅ 正确姿势:Priority 与 Sizes
Next.js 的 <Image> 组件是性能优化的神器,前提是你要会用。

<div className="relative h-[500px] w-full">
<Image
src="/hero-banner.png"
alt="Hero Banner"
fill
style={{ objectFit: 'cover' }}
priority={true} // 优化点 1:LCP 强心剂
sizes="(max-width: 768px) 100vw,
(max-width: 1200px) 50vw,
33vw" // 优化点 2:按需下载
quality={85} // 优化点 3:平衡画质与体积
placeholder="blur" // 优化点 4:视觉稳定性
blurDataURL="data:image/..."
/>
</div>
深度解析:
- priority={true}:这会给
<img />加上fetchPriority="high"属性,并在<head>中生成preload链接。它告诉浏览器:“别管 JS 了,先下载这张图!”这对提升 LCP 立竿见影。 - sizes:很多开发者只写宽和高,忽略了
sizes。sizes属性告诉浏览器在不同屏幕宽度下,这张图片大概有多宽。配合 Next.js 自动生成的srcset,浏览器就能智能选择下载 300px 的缩略图还是 1024px 的大图。
2. CLS 杀手:字体加载与 FOUT/FOIT
你有没有遇到过:页面打开,文字先是系统默认字体(比如宋体),0.5 秒后突然闪烁变成了你自定义的可爱字体?或者更惨,文字隐形了 0.5 秒才出来?
这就是 FOUT (Flash of Unstyled Text) 和 FOIT (Flash of Invisible Text)。它们不仅难看,还会导致内容高度变化,引发布局偏移 (CLS)。
✅ 解决方案:next/font
next/font 是 Next.js 13 引入的杀手级特性。它会在 构建时 (Build Time) 自动下载 Google Fonts 或本地字体,并将字体文件和 CSS 内联到项目中。
这意味着:没有任何发往 fonts.googleapis.com 的外部请求。你的字体和 HTML 是同时到达用户浏览器的。
更神奇的是它的 adjustFontFallback 特性。
import { Inter, Lora } from 'next/font/google';
// 定义字体,开启 subset 减少体积
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter',
});
const lora = Lora({
subsets: ['latin'],
variable: '--font-lora',
});
export default function RootLayout({ children }) {
return (
<html lang="en" className={`${inter.variable} ${lora.variable}`}>
<body className="font-sans antialiased">
{children}
</body>
</html>
);
}
Next.js 会自动计算系统字体(Arial/Times)和你的自定义字体(Inter/Lora)之间的宽高比差异,通过 CSS size-adjust 属性,强制让后备字体占据和自定义字体一模一样的空间。这样,即使自定义字体没加载完,布局也不会抖动!
3. 架构级优化:局部预渲染 (PPR)
如果说前面的优化是修修补补,那么 局部预渲染 (Partial Prerendering, PPR) 就是架构层面的降维打击。
在 Next.js 14 之前,我们只能二选一:
- 静态 (SSG):极致速度,CDN 边缘缓存。但数据陈旧,无法千人千面。
- 动态 (SSR):实时数据,个性化。但首屏慢,因为要等数据库查询完才返回 HTML。TTFB (首字节时间) 高导致 LCP 高。
PPR 允许你将两者 混合:

import { Suspense } from 'react';
import { ProductSkeleton } from './skeletons';
import { RecommendedProducts } from './recommendations';
// 页面外壳:这是静态的!瞬间返回 200 OK!
export default function Page() {
return (
<main>
<h1>My Static Product Page</h1>
<p>This part is static and served from CDN instantly.</p>
{/* 动态空洞:这是动态的! */}
<Suspense fallback={<ProductSkeleton />}>
{/* 这个组件里包含了 await db.query() */}
<RecommendedProducts />
</Suspense>
</main>
);
}
开启 PPR 后,用户请求页面,服务器会 立刻 返回静态外壳(包含导航栏、Footer、静态文案和骨架屏)。浏览器立刻开始渲染,LCP 几乎为 0。同时,服务器并行开始计算动态部分 (Stream),计算好一点就通过 HTTP Stream 推送一点给浏览器填补空洞。
这是目前 Web 性能优化的终极形态。
4. 第三方脚本噩梦:Script 优化
我们免不了要接入 Google Analytics、Meta Pixel、客服插件等。这些第三方脚本往往体积巨大、加载缓慢,且阻塞主线程。
Next.js 的 <Script> 组件提供了 strategy 属性来管理加载时机。
import Script from 'next/script';
// strategy="afterInteractive" (默认):页面水合后立即加载 (适合 GA)
<Script src="https://www.google-analytics.com/..." />
// strategy="lazyOnload": 浏览器空闲时才加载 (适合客服聊天窗口)
// 这能显著降低 TBT (Total Blocking Time)
<Script
src="https://chat-widget.com/..."
strategy="lazyOnload"
/>
// strategy="worker" (实验性): 将脚本扔到 Web Worker 中运行
// 完全脱离主线程,适合纯计算逻辑
<Script
src="..."
strategy="worker"
/>
5. 减肥药:@next/bundle-analyzer
有时候你的 JS 包体积变大,仅仅是因为你不小心引入了一个巨大的库(比如引入了完整的 lodash 而不是 lodash/get,或者引入了整个 moment.js)。
定期运行 Bundle Analyzer 是必修课。
- 安装:
npm install @next/bundle-analyzer - 配置
next.config.js:
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({
// your next config
});
- 运行:
ANALYZE=true npm run build
你会看到一张五颜六色的矩形图。对着最大的方块切下去。常见的优化手段:
- Tree Shaking:确保只引入需要的函数 (Named Import)。
- Dynamic Import:对于首屏不需要的重型组件(如富文本编辑器、3D 模型查看器),使用
next/dynamic懒加载。
const HeavyChart = dynamic(() => import('./HeavyChart'), {
loading: () => <p>Loading Chart...</p>,
ssr: false, // 如果不需要 SEO,关掉 SSR 可以进一步减小 HTML 体积
});
总结
性能优化不是玄学,是对浏览器渲染机制的尊重。记住三条原则:
- 重要的东西优先加载 (LCP / Priority / Preload)。
- 占好位置别乱动 (CLS / Fonts / 宽高比)。
- 别堵塞主线程 (Script Strategy / Web Worker)。
只要做对了这几点,你的 Next.js 应用不仅 Lighthouse 分数高,更能给用户带来丝般顺滑的体验。