mcpField
N
nextjs-performance

nextjs-performance

github.com/giuseppe-trisciuoglio开发3654.9k 次安装7 周前更新
代码仓库

关于 nextjs-performance

面向 Next.js 应用开发者的性能优化指南,涵盖 Core Web Vitals、组件模式、缓存和精简打包体积,也包含 Next.js 16 与 React 19 的实践。

主要功能

  1. 01Core Web Vitals 优化
  2. 02图像与字体优化
  3. 03缓存与重新验证
  4. 04Server Component 模式
  5. 05使用 Suspense 流式加载
  6. 06打包分析与精简

适用场景

  1. 01改善 LCP、INP 或 CLS
  2. 02减少客户端 JavaScript
  3. 03加快重复数据加载
  4. 04缩减初始打包体积

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill nextjs-performance

安装后在 Claude Code 中输入/nextjs-performance确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api-routes.md
bundle-optimization.md
caching-strategies.md
core-web-vitals.md
font-optimization.md
image-optimization.md
metadata-seo.md
nextjs-16-patterns.md
server-components.md
streaming-suspense.md

详细介绍

Next.js 性能优化

为优化 Next.js 应用提供专家指导,重点关注 Core Web Vitals、现代模式和最佳实践。

概述

此技能为优化 Next.js 应用提供全面指导,涵盖 Core Web Vitals 优化(LCP、INP、CLS)、现代 React 模式、Server Components、缓存策略和包优化技术。适用于已熟悉 React/Next.js,并希望实施生产级优化的开发者。

适用场景

在处理 Next.js 应用且需要进行以下操作时,使用此技能:

  • 优化 Core Web Vitals(LCP、INP、CLS),提升性能和 SEO
  • 使用 next/image 实现图像优化,加快加载速度
  • 使用 next/font 配置字体优化,消除布局偏移
  • 使用 unstable_cache、revalidateTag 或 ISR 设置缓存策略
  • 将 Client Components 转换为 Server Components,以缩小包体积
  • 实现 Suspense 流式传输,实现渐进式页面加载
  • 使用代码拆分和动态导入分析并减小包体积
  • 配置元数据和 SEO,提升搜索引擎可见性
  • 优化 API 路由处理程序,提升性能
  • 应用 Next.js 16 和 React 19 的现代模式
涵盖领域
  • Core Web Vitals 优化(LCP、INP、CLS)
  • 使用 next/image 进行图像优化
  • 使用 next/font 进行字体优化
  • 缓存策略(unstable_cache、revalidateTag、ISR)
  • Server Components 模式及从客户端到服务端的转换
  • 流式传输和 Suspense,实现渐进式加载
  • 包优化和代码拆分
  • 元数据和 SEO 配置
  • 路由处理程序优化
  • Next.js 16 + React 19 模式

使用说明

开始之前
  1. 使用 Lighthouse 分析当前性能
  2. 找出瓶颈——在 Chrome DevTools 或 PageSpeed Insights 中检查 Core Web Vitals
  3. 确定优化优先级:
    • LCP 问题 → 重点优化图像和字体
    • INP 问题 → 减少 JavaScript,使用 Server Components
    • CLS 问题 → 添加尺寸,使用 next/font
如何使用此技能
  1. 根据要优化的领域,加载相关参考文件:

    • 图像问题 → references/image-optimization.md
    • 字体/布局偏移 → references/font-optimization.md
    • 缓存 → references/caching-strategies.md
    • 组件架构 → references/server-components.md
  2. 按照常见优化的快速模式操作

  3. 应用改进前后的转换来优化现有代码

  4. 更改后使用 Lighthouse 验证改进效果

核心原则
  1. 优先使用 Server Components——仅在必要时使用 'use client'(浏览器 API、交互功能)
  2. 尽可能降低组件加载层级——将 Client Components 保留在叶节点
  3. 使用 Suspense 边界——启用流式传输和渐进式加载
  4. 合理缓存——使用标签进行精细化重新验证
  5. 测量改进前后效果——始终使用实际指标验证改进

示例

示例 1:将 Client Component 转换为 Server Component

之前(带有 useEffect 的 Client Component):

'use client'
import { useEffect, useState } from 'react'

export default function ProductList() {
  const [products, setProducts] = useState([])

  useEffect(() => {
    fetch('/api/products').then(r => r.json()).then(setProducts)
  }, [])

  return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>
}

之后(直接访问数据的 Server Component):

import { db } from '@/lib/db'

export default async function ProductList() {
  const products = await db.product.findMany()
  return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>
}
示例 2:优化图像以改善 LCP
import Image from 'next/image'

export function Hero() {
  return (
    <div className="relative w-full h-[600px]">
      <Image
        src="/hero.jpg"
        alt="Hero"
        fill
        priority          // Disable lazy loading for LCP
        sizes="100vw"
        className="object-cover"
      />
    </div>
  )
}
示例 3:实施缓存策略
import { unstable_cache, revalidateTag } from 'next/cache'

// Cached data function
const getProducts = unstable_cache(
  async () => db.product.findMany(),
  ['products'],
  { revalidate: 3600, tags: ['products'] }
)

// Revalidate on mutation
export async function createProduct(data: FormData) {
  'use server'
  await db.product.create({ data })
  revalidateTag('products')
}
示例 4:设置优化字体
import { Inter } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
})

export default function RootLayout({ children }) {
  return (
    <html lang="en" className={inter.variable}>
      <body className={`${inter.className} antialiased`}>
        {children}
      </body>
    </html>
  )
}
示例 5:实现 Suspense 流式传输
import { Suspense } from 'react'

export default function Page() {
  return (
    <>
      <header>Static content (immediate)</header>

      <Suspense fallback={<ProductSkeleton />}>
        <ProductList />  {/* Streamed when ready */}
      </Suspense>

      <Suspense fallback={<ReviewsSkeleton />}>
        <Reviews />      {/* Independent streaming */}
      </Suspense>
    </>
  )
}

参考文档

针对特定领域的工作,请加载以下参考文档:

主题参考文件
Core Web Vitalsreferences/core-web-vitals.md
图片优化references/image-optimization.md
字体优化references/font-optimization.md
缓存策略references/caching-strategies.md
服务端组件references/server-components.md
流式传输/Suspensereferences/streaming-suspense.md
Bundle 优化references/bundle-optimization.md
元数据/SEOreferences/metadata-seo.md
API 路由references/api-routes.md
Next.js 16 模式references/nextjs-16-patterns.md

常见转换

从转换为优势
useEffect + fetch服务端组件中的直接异步操作减少 70% 的 JS,更快的 TTFB
使用 useState 管理数据可直接访问数据库的服务端组件代码更简洁,无需水合
客户端 fetchunstable_cache 或 ISR重复加载更快
img 标签next/image优化的格式、延迟加载
CSS 字体导入next/fontCLS 为零,自动优化
重型组件的静态导入dynamic()减少初始 Bundle

最佳实践

图片
  • 所有图片都使用 next/image
  • 仅为 LCP 图片添加 priority
  • 提供 width 和 height,或使用带 sizes 的 fill
  • 使用 placeholder="blur" 改善用户体验
  • 在 next.config.js 中配置 remotePatterns
字体
  • 使用 next/font,而不是 CSS 导入
  • 指定 subsets 以减小体积
  • 使用 display: 'swap' 立即渲染文本
  • 使用 variable 选项创建 CSS 变量
  • 配置 Tailwind 使用 CSS 变量
缓存
  • 使用 unstable_cache 缓存开销较大的查询
  • 使用有意义的缓存标签进行精细控制
  • 为动态内容实施按需重新验证
  • 根据数据变化频率设置 TTL
  • 使用 revalidatePath 进行路由级失效处理
组件
  • 尽可能将客户端组件转换为服务端组件
  • 将客户端组件放在组件树的叶子层级
  • 使用 Suspense 边界实现渐进式加载
  • 实施适当的加载状态
  • 对首屏以下的重型组件使用 dynamic()
Bundle
  • 使用 dynamic() 延迟加载重型组件
  • 使用具名导出以改善 tree shaking
  • 定期使用 @next/bundle-analyzer 分析 Bundle
  • 优先使用 ESM 包,而不是 CommonJS
  • 对大型库使用 modularizeImports

限制和警告

服务端组件的限制
  • 不能使用浏览器 API(window、localStorage、document)
  • 不能使用 React Hook(useState、useEffect、useContext)
  • 不能使用事件处理程序(onClick、onSubmit)
  • 不能使用带有 ssr: false 的动态导入
图片优化限制
  • priority 只能用于首屏图片
  • 外部图片需要在 next.config.js 中配置
  • 除非使用 fill,否则必须提供 width 和 height
  • 默认不会优化动态 GIF
缓存注意事项
  • 必须手动使缓存标签失效
  • 开发环境中的数据缓存按请求隔离
  • Edge 运行时的缓存行为有所不同
  • 缓存用户专属数据时要谨慎
Bundle 大小警告
  • 如果关键内容使用动态导入,可能会影响 SEO
  • Tree shaking 需要正确使用 ES 模块
  • 某些库无法进行 tree shaking(避免使用 barrel 导出)
  • 客户端组件会增大 Bundle 体积,请谨慎使用

Next.js 16 + React 19 特定内容

异步参数
// Next.js 15+ params is a Promise
export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  const post = await fetchPost(slug)
  return <article>{post.content}</article>
}
用于 Promise 的 use() Hook
'use client'
import { use, Suspense } from 'react'

function Comments({ promise }: { promise: Promise<Comment[]> }) {
  const comments = use(promise)  // Suspend until resolved
  return <ul>{comments.map(c => <li key={c.id}>{c.text}</li>)}</ul>
}
用于更新 UI 的 useOptimistic
'use client'
import { useOptimistic } from 'react'

export function TodoList({ todos }: { todos: Todo[] }) {
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo: Todo) => [...state, newTodo]
  )

  async function addTodo(formData: FormData) {
    const text = formData.get('text') as string
    addOptimisticTodo({ id: crypto.randomUUID(), text, completed: false })
    await createTodo(text)
  }

  return (
    <form action={addTodo}>
      <input name="text" />
      {optimisticTodos.map(todo => <div key={todo.id}>{todo.text}</div>)}
    </form>
  )
}

Bundle 分析

# Install analyzer
npm install --save-dev @next/bundle-analyzer

# Run analysis
ANALYZE=true npm run build
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
})

module.exports = withBundleAnalyzer({
  modularizeImports: {
    'lodash': { transform: 'lodash/{{member}}' },
  },
})

性能检查清单

  • 所有图片都使用 next/image 并设置了适当的尺寸
  • LCP 图片具有 priority 属性
  • 字体使用 next/font 并指定子集
  • 尽可能使用服务端组件
  • 客户端组件仅用于叶节点
  • 为数据获取设置 Suspense 边界
  • 为开销较大的操作配置缓存
  • 分析打包内容,检查是否存在重复项
  • 对大型组件进行懒加载
  • 使用 Lighthouse 验证优化前后的得分

常见错误

// ❌ DON'T: Fetch in useEffect
'use client'
useEffect(() => { fetch('/api/data').then(...) }, [])

// ✅ DO: Fetch directly in Server Component
const data = await fetch('/api/data')

// ❌ DON'T: Forget dimensions on images
<Image src="/photo.jpg" />

// ✅ DO: Always provide dimensions
<Image src="/photo.jpg" width={800} height={600} />

// ❌ DON'T: Use priority on all images
<Image src="/photo1.jpg" priority />
<Image src="/photo2.jpg" priority />

// ✅ DO: Priority only for LCP
<Image src="/hero.jpg" priority />
<Image src="/photo.jpg" loading="lazy" />

// ❌ DON'T: Cache everything with same TTL
{ revalidate: 3600 }

// ✅ DO: Match TTL to data change frequency
{ revalidate: 86400 } // Categories rarely change
{ revalidate: 60 }     // Comments change often

外部资源

评论

支持 Markdown