React / TypeScript 工程师 是做什么的?
Next.js 变化很快,模型记忆常常过时。在使用任何依赖版本的 API 之前,请检查 references/versions.md。如果已安装的 next 包含了捆绑文档(node_modules/next/dist/docs/)或 Next.js 生成的 AGENTS.md,请优先使用这些文档而非记忆。
第 0 步:检测版本和约定(始终执行)
运行 bash scripts/detect_versions.sh(只读),然后确认:
-
package.json+ 锁文件 (pnpm/npm/yarn/bun) → next, react, typescript, tailwindcss, 测试工具;使用锁文件对应的包管理器 -
next.config.*→cacheComponents,partialPrefetching,reactCompiler,experimental.* - 路由:
app/与src/app/,是否有pages/(混合路由),proxy.ts与旧版middleware.ts - 数据层:ORM/SDK,现有的
lib/dal.ts或server-only模块,认证库 - 样式和 UI 工具包(Tailwind 版本,CSS Modules, shadcn/ui, 设计令牌),lint/format(ESLint flat config 与 Biome)
- 测试:Vitest/Jest, Testing Library, Playwright;现有的 CI 脚本
匹配现有约定。如果项目使用的是较旧的次版本,请编写适用于该版本的代码。
默认设置(每个决策一个,带逃生舱)
| 决策 | 默认值 | 何时使用替代方案 |
|---|---|---|
| 组件类型 | Server Component | 需要状态、副作用、浏览器 API 或事件处理程序 → 在最小的叶子节点使用 "use client" |
| 缓存模型 (16.x) | Cache Components (cacheComponents: true, 'use cache' + cacheLife/cacheTag) | 现有应用使用旧模型且无迁移计划。不要半途而废 |
| 数据变更 | Server Actions + revalidateTag/updateTag/refresh | 公共 API 被其他客户端使用 → 路由处理器 |
| 数据访问 | 一个仅服务端的数据访问层 (DAL),对每次读/写进行认证和授权 | — |
| 请求拦截 | proxy.ts 仅用于重定向/重写/标头 | 绝不用作唯一的授权检查 |
| 运行时 | Node.js (默认) | 16.3+ 中无:runtime = 'edge' 已被弃用/不支持 |
| 表单 | <form action={serverAction}> + useActionState + 服务端 schema 验证 (zod 或项目的) | 复杂的纯客户端向导 → 使用项目中已有的客户端表单库 |
| 样式 | 项目的样式系统;对于新项目,使用 Tailwind CSS v4 及 CSS 优先配置 | — |
| 客户端状态 | URL 搜索参数 → 服务端状态 → React 状态;仅当证明必要时才使用全局存储 | — |
| 记忆化 | React Compiler(如果启用);否则仅对测量到的热点进行记忆化 | — |
| 测试 | Vitest + Testing Library 用于单元测试;Playwright 用于 E2E 关键流程 | 如果已配置 Jest |
工作流程 A:构建路由或功能
- [ ] 第 0 步已完成
- [ ] 路由段:根据需要创建 page.tsx, layout.tsx, loading.tsx/Suspense 边界, error.tsx, not-found.tsx
- [ ] 通过 DAL(仅服务端)获取数据,在 Server Components 中 await;params/searchParams 是 Promises:`const { id } = await params`
- [ ] 决定哪些是缓存的('use cache' + cacheLife/cacheTag)与请求时获取的(在 Suspense 内部)
- [ ] 通过 Server Actions 处理数据变更:验证输入,在 action 中重新检查权限,重新验证标签
- [ ] Client Components 保持最小;props 可序列化;无秘密泄露到客户端包中(只有 NEXT_PUBLIC_* 会到达浏览器)
- [ ] 无障碍:语义化元素、标签、焦点管理、键盘路径、色彩对比度
- [ ] 为逻辑编写测试 + 为关键路径编写一个 E2E 测试
- [ ] 验证循环通过
验证 → 修复 → 重复:
pnpm exec tsc --noEmit # 或 npm/yarn/bun 的等效命令
pnpm lint # 根据项目使用 ESLint 或 Biomen (next lint 已在 16 中移除)
pnpm test -- --run # Vitest
pnpm build # 捕获 Cache Components / 预渲染错误
pnpm exec playwright test # 当存在 E2E 测试时
next build 关于“在 <Suspense> 外部未缓存数据”的错误是信号,不是噪音。通过添加 'use cache'、将访问移入 Suspense 边界或将其标记为请求时获取来修复。
工作流程 B:升级 Next.js(低自由度)
- [ ] 阅读 references/versions.md 中的“旧模式”和安全最低版本
- [ ] 提交一个干净的工作树;创建一个分支
- [ ] 运行官方升级工具:`npx next@canary upgrade --agent=latest`
(如果代理流程不可用,则使用 `npx @next/codemod@canary upgrade latest`)
- [ ] 将 react、react-dom 和 @types/react 与 next 一起升级
- [ ] 移除 `runtime = 'edge'` 导出;将 middleware.ts 重命名为 proxy.ts(Node 运行时)
- [ ] 验证循环;然后手动冒烟测试身份验证、重定向、缓存和重新验证
安全优先:如果安装的版本低于 versions.md 中列出的修补版本,请升级 next 本身(仅修补 React 包是不够的)。
工作流程 C:在现有应用中采用 Cache Components
逐个路由迁移。在一个分支上启用 cacheComponents(以及在 16.4+ 上启用 partialPrefetching),运行 next build,并修复每个报告的错误边界。请参阅 references/caching.md。如果已安装,Next.js 的 next-cache-components-adoption 技能会深入介绍具体机制;请同时使用它。
认证与安全规则
- 在 DAL 中以及每个 Server Action 和路由处理器中进行授权。代理/中间件检查仅用于优化重定向。CVE-2025-29927 表明基于标头绕过中间件是可能的。
- Server Actions 是公共 HTTP 端点:验证输入,检查会话,检查所有权。
- 在包含秘密或数据库访问的模块中导入
server-only;向 Client Components 返回 DTO(仅包含必要字段)。 - 详细信息:
references/data-and-auth.md。
从设计或原型实现
- 盘点设计:令牌(颜色、字体大小、间距、圆角)、组件、状态(悬停、聚焦、禁用、加载、空、错误)和断点。
- 首先将其映射到项目现有的令牌和组件;将新令牌添加到主题,而不是作为一次性值。
- 首先构建静态 Server Components 标记,然后在叶子节点添加交互。
- 检查 320px、平板和桌面宽度。检查键盘和屏幕阅读器标签。尊重
prefers-reduced-motion。 - 如果有浏览器工具或 Playwright 可用,截图并与原型比较;迭代直到间距和排版匹配。
审查模式
使用 references/review-checklist.md。将每个发现报告为 阻断 / 应修复 / 注意,并附带文件:行号、问题描述以及具体的代码修复方案。按严重程度排序发现项。阻断项包括:仅在代理中进行身份验证、秘密泄露到客户端包中、未经验证的 Server Action 输入、易受攻击的 next 版本以及共享的 'use cache' 作用域内的用户特定数据。
参考地图
references/versions.md:版本、安全最低版本、旧模式、验证说明references/data-and-auth.md:DAL 模式、Server Action 模板、会话处理references/caching.md:Cache Components 规则、ensureStatic、navigation()/prefetch()references/review-checklist.md:按影响排序的规则