Next.js 提供了许多内置的优化功能,但理解这些功能的工作原理以及如何进一步优化应用仍然很重要。在这一节课,我们将学习如何优化缓存策略,如何实现代码分割和懒加载,如何优化图片和字体,以及如何监控应用性能。

Next.js 使用了多层缓存机制来提升性能:
fetch 请求只会执行一次,结果会被缓存并在组件之间共享。fetch 请求的结果默认会被缓存,除非明确指定不缓存。cache 函数包装的函数调用会被缓存。让我们看一个例子:
|// app/products/page.tsx import { cache } from 'react'; const getProducts = cache(async () => { const response = await fetch('https://api.example.com/products', { next: { revalidate: 3600 }, // 缓存 1 小时 }); return response.json(); }); export default async function ProductsPage() { const products = await getProducts(); return ( <div> {products.map((product) => ( <div key={product.id}>{product.name}</div> ))} </div> ); }
这个例子使用了 cache 函数和 revalidate 选项。cache 确保在同一个渲染过程中只执行一次请求,revalidate 则控制缓存的有效期。
Next.js 自动进行代码分割,每个路由都会生成独立的 JavaScript 包。但我们也可以手动进行代码分割,使用动态导入:
|// app/components/HeavyComponent.tsx 'use client'; import { lazy, Suspense } from 'react'; const HeavyChart = lazy(() => import('./HeavyChart')); export default function HeavyComponent() { return ( <Suspense fallback={<div>加载中...</div>}> <HeavyChart /> </
这个例子使用 lazy 和 Suspense 来懒加载一个重型组件。组件只会在需要时加载,减少初始包大小。
对于第三方库,我们也可以使用动态导入,例如:
|// app/components/DataVisualization.tsx 'use client'; import { useState, useEffect } from 'react'; export default function DataVisualization() { const [Chart, setChart] = useState<any>(null); useEffect(() => { import('react-chartjs-2').then((mod)
这个例子在客户端动态加载图表库,只有在需要时才加载,减少初始包大小。
图片通常是页面中最大的资源。Next.js 的 Image 组件提供了自动优化,但我们还可以进一步优化:
首先,使用合适的图片格式。Next.js 会自动转换为 WebP 或 AVIF,但我们可以手动指定:
|// app/components/OptimizedImage.tsx import Image from 'next/image'; export default function OptimizedImage({ src }: { src: string }) { return ( <Image src={src} alt="图片" width={800} height={600}
其次,使用 sizes 属性来优化响应式图片:
|// app/components/ResponsiveImage.tsx import Image from 'next/image'; export default function ResponsiveImage() { return ( <Image src="/banner.jpg" alt="横幅" width={1920} height={1080} sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" /> ); }
Next.js 的 next/font(例如 next/font/google)通过自动拆分字体、子集化 (subsetting) 以及支持懒加载方式,已经大幅提升了字体加载和渲染性能。但实际项目中,我们还可以结合以下方式进一步优化字体表现和用户体验:
display: 'swap':让页面优先用系统字体渲染,等 web 字体加载完即无缝切换,可显著减少页面文字闪烁(FOIT/FOUT)。preload: true:将 web 字体声明为预加载资源,让浏览器更早请求字体,提升首屏渲染速度。subsets 和 fallback:通过合适的字符集子集,精简字体包大小,并设置可靠的备用字体确保兼容性。|// app/layout.tsx import { Inter } from 'next/font/google'; const inter = Inter({ subsets: ['latin'], display: 'swap', // 使用 swap 避免文字闪烁 preload: true, // 预加载字体 fallback: ['system-ui', 'arial'], // 备用字体 }); export default function RootLayout({ children, }:
display: 'swap' 告诉浏览器在字体加载时使用备用字体,避免文字闪烁。preload: true 会预加载字体,提升首屏性能。
对于页面渲染时最重要、优先级最高的资源(如首屏样式表、英雄图像、关键脚本等),我们可以使用 <link rel="preload"> 标签进行预加载。这能让浏览器在渲染前尽早并行请求这些资源,从而加快页面加载和首屏渲染速度。例如,可以在 <head> 中添加如下代码来预加载关键 CSS 和图片:
|// app/layout.tsx export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html> <head> <link rel="preload" href="/critical.css" as="style" /> <link
Next.js 的 Link 组件会自动预取链接的页面,但别忘了之前学到的,我们也可以手动控制是否进行预加载:
|// app/components/Navigation.tsx import Link from 'next/link'; export default function Navigation() { return ( <nav> <Link href="/about" prefetch={true}>关于</Link> <Link href="/contact" prefetch={false}>联系</Link>
监控应用的性能对于及时发现性能瓶颈和优化用户体验至关重要。我们通常需要持续、详细地收集性能数据,以便定位问题并评估优化效果。可以借助 Web Vitals 标准,它关注用户实际体验的核心指标(如页面加载速度、交互延迟和视觉稳定性)。 Web Vitals 包括 CLS(累积布局偏移)、FID(首次输入延迟)、LCP(最大内容绘制)、FCP(首次内容绘制)、TTFB(首字节时间)等。通过将这些指标采集并上报到后端或监控平台,我们能够持续跟踪网站在真实用户端的表现,及时发现和修复潜在问题,并针对性地优化性能。
|// app/layout.tsx import { Analytics } from '@vercel/analytics/react'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html> <body> {children} <Analytics /> </body>
或者使用自定义的监控:
|// app/components/WebVitals.tsx 'use client'; import { useEffect } from 'react'; import { onCLS, onFID, onFCP, onLCP, onTTFB } from 'web-vitals'; export default function WebVitals() { useEffect(() => { onCLS(console.log); onFID(console.log); onFCP(console.log); onLCP(console.log); onTTFB(console.log); }, []); return
这个例子监控了所有核心 Web Vitals 指标:CLS(累积布局偏移)、FID(首次输入延迟)、FCP(首次内容绘制)、LCP(最大内容绘制)、TTFB(首字节时间)。
在这一部分,我们深入探索了 Next.js 的性能优化。我们学习了如何优化缓存策略,如何实现代码分割和懒加载,如何优化图片和字体,以及如何监控应用性能。 性能优化是一个持续的过程,需要根据实际使用情况不断调整。通过合理使用 Next.js 的优化功能,我们可以创建既快速又高效的应用。
在下一节课,我们将学习部署和构建,了解如何部署 Next.js 应用到 Vercel 和其他平台,如何配置环境变量,以及如何优化构建过程。