Published on
Word count
338 字 · 阅读约 2 分钟

Next.js App Router 性能优化实战

Authors
  • avatar
    Name
    眠月
    Twitter

Server Components:减少客户端 JavaScript

Next.js App Router 最大的变革是默认使用 Server Components。这意味着:

// 这个组件在服务端渲染,零客户端 JS
async function BlogList() {
  const posts = await db.posts.findMany()
  
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

什么时候用 Client Components?

只有需要交互、状态、或浏览器 API 时才标记 'use client':

'use client'

import { useState } from 'react'

export function SearchBar() {
  const [query, setQuery] = useState('')
  
  return (
    <input
      value={query}
      onChange={e => setQuery(e.target.value)}
      placeholder="搜索文章..."
    />
  )
}

关键原则:把 Client Component 推到叶子节点,让尽可能多的组件留在服务端。

Streaming SSR:渐进式渲染

使用 loading.tsx 和 Suspense 实现流式渲染:

// app/blog/loading.tsx
export default function Loading() {
  return <BlogSkeleton />
}

// 精细控制
import { Suspense } from 'react'

export default function BlogPage() {
  return (
    <div>
      <h1>博客</h1>
      <Suspense fallback={<BlogSkeleton />}>
        <BlogList />
      </Suspense>
    </div>
  )
}

图片优化

Next.js Image 组件的优化策略:

import Image from 'next/image'

<Image
  src="/hero.jpg"
  alt="Hero"
  width={1200}
  height={630}
  priority  // 首屏图片立即加载
  placeholder="blur"  // 模糊占位
  sizes="(max-width: 768px) 100vw, 50vw"
/>

字体优化

import { Inter } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',  // 避免 FOIT
})

数据获取策略

静态生成(推荐博客内容)

// 构建时获取数据
async function getPosts() {
  const res = await fetch('https://api.example.com/posts')
  return res.json()
}

增量静态再生 (ISR)

// 每60秒重新验证
fetch('https://api.example.com/posts', {
  next: { revalidate: 60 }
})

性能检查清单

  • Lighthouse 评分 > 90
  • LCP < 2.5s
  • CLS < 0.1
  • 使用 Route Segment Config 控制缓存策略
  • 启用 Partial Prerendering (PPR)
  • 图片全部使用 next/image
  • 字体使用 next/font 自托管