name: Next.js最佳实践
description: Next.js App Router 原则。服务器组件、数据获取、路由模式。
allowed-tools: 读、写、编辑、全局、Grep
license: MIT
metadata:
version: “1.0.0”
domain: 前端
triggers: Next.js, App Router, 服务器组件, 数据获取, 路由
role: 专家
scope: 实现
output-format: 代码
related-skills: nextjs-app-router-patterns, nextjs-developer, react-expert
Next.js最佳实践
Next.js App Router 开发的原则。
1. 服务器 vs 客户端组件
决策树
是否需要...?
│
├── useState, useEffect, 事件处理程序
│ └── 客户端组件 ('use client')
│
├── 直接数据获取,无交互性
│ └── 服务器组件 (默认)
│
└── 两者都需要?
└── 拆分:服务器父组件 + 客户端子组件
默认情况
| 类型 |
用途 |
| 服务器组件 |
数据获取、布局、静态内容 |
| 客户端组件 |
表单、按钮、交互式UI |
2. 数据获取模式
获取策略
| 模式 |
用途 |
| 默认 |
静态(构建时缓存) |
| 重新验证 |
ISR(基于时间刷新) |
| 无存储 |
动态(每次请求) |
数据流
| 来源 |
模式 |
| 数据库 |
服务器组件获取 |
| API |
使用缓存的 fetch |
| 用户输入 |
客户端状态 + 服务器操作 |
3. 路由原则
文件约定
| 文件 |
目的 |
page.tsx |
路由UI |
layout.tsx |
共享布局 |
loading.tsx |
加载状态 |
error.tsx |
错误边界 |
not-found.tsx |
404页面 |
路由组织
| 模式 |
用途 |
路由组 (name) |
组织但不影响URL |
并行路由 @slot |
多个同级别页面 |
拦截路由 (.) |
模态覆盖 |
4. API 路由
路由处理器
| 方法 |
用途 |
| GET |
读取数据 |
| POST |
创建数据 |
| PUT/PATCH |
更新数据 |
| DELETE |
删除数据 |
最佳实践
- 使用 Zod 验证输入
- 返回适当的状态码
- 优雅处理错误
- 尽可能使用 Edge 运行时
5. 性能原则
图像优化
- 使用 next/image 组件
- 为视口上方设置优先级
- 提供模糊占位符
- 使用响应式尺寸
包优化
- 对重型组件使用动态导入
- 基于路由的代码分割(自动)
- 使用包分析器分析
6. 元数据
静态 vs 动态
| 类型 |
用途 |
| 静态导出 |
固定元数据 |
| generateMetadata |
每个路由的动态元数据 |
基本标签
- 标题(50-60字符)
- 描述(150-160字符)
- Open Graph 图像
- 规范URL
7. 缓存策略
缓存层
| 层 |
控制 |
| 请求 |
fetch 选项 |
| 数据 |
重新验证/标签 |
| 完整路由 |
路由配置 |
重新验证
| 方法 |
用途 |
| 基于时间 |
revalidate: 60 |
| 按需 |
revalidatePath/Tag |
| 无缓存 |
no-store |
8. 服务器操作
使用场景
最佳实践
- 使用 ‘use server’ 标记
- 验证所有输入
- 返回类型化响应
- 处理错误
9. 反模式
| ❌ 不要 |
✅ 做 |
| 到处使用 ‘use client’ |
默认使用服务器组件 |
| 在客户端组件中获取数据 |
在服务器中获取 |
| 跳过加载状态 |
使用 loading.tsx |
| 忽略错误边界 |
使用 error.tsx |
| 大型客户端包 |
使用动态导入 |
10. 项目结构
app/
├── (marketing)/ # 路由组
│ └── page.tsx
├── (dashboard)/
│ ├── layout.tsx # 仪表板布局
│ └── page.tsx
├── api/
│ └── [resource]/
│ └── route.ts
└── components/
└── ui/
记住: 服务器组件是默认是有原因的。从那里开始,仅在需要时添加客户端。