Communitygithub.com

rbikbov/frontend-starter

启动一个新的 Next.js (App Router) + TypeScript 前端项目:在实现第一个功能之前奠定基础。用于需要从零创建项目、决定是否需要 Next.js、Monorepo、BFF、微前端、在 Next 路由上组织 FSD、配置严格的 TypeScript、边界 lint、环境变量配置、错误模型与 API 客户端、测试、Git hooks、CI、README 骨架,或在使用生成器后的早期项目中建立秩序的场景。

frontend-starter 是什么?

该技能为 AI 代理(如 Claude Code、Cursor、Codex)提供了一个系统化的起始步骤清单,用于启动符合生产标准的 Next.js (App Router) + TypeScript 项目。它优先通过清晰的决策树、严格的文件夹结构(基于 Feature-Sliced Design,FSD)以及一套强制性的配置(包括边界 lint、环境变量验证 Schema、标准化的错误处理模型和 API 客户端)来避免技术债务。该技能支持在 Vercel、独立 Node 服务器或 Docker 上部署,并整合了 Vitest、Playwright、MSW、Git hooks(husky、lint-staged、commitlint)以及 CI/CD 流水线(GitHub Actions)。其核心原则是“按需引入”和“基于已安装包的官方文档”来确保可维护性,并提供了详细的核对清单和最佳实践解释,因此特别适用于从零搭建或重构混乱的生成器项目。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/rbikbov/frontend-starter/tree/HEAD/.claude/skills/frontend-bootstrap

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

启动 Next.js 项目

基础最好在第一天就打好:之后每个规则都必须强行施加到违反它的代码之上。如果有 frontend-starter 模板——请从复制模板开始: 模板中的步骤已经完成并经过验证,本文档仅作为决策解释和审计检查清单。本文档设定了步骤顺序和最小集。如何编写代码本身——请看 fsd-frontend 技能(如果项目中有);授权相关——frontend-auth-session;提交前检查——anti-slop-review。现成配置——references/configs.md,Next + FSD 的结构示例和代码——references/next-structure.md。

规则优先级。 用户的明确指令和项目代理文件(AGENTS.md、CLAUDE.md)优先于本文档。库版本会变化:复制配置前,请对照已安装版本的文档,并且在运行之前不要声称它能工作。

关于 Next.js 的事实——来自包中的文档,而非本文档或记忆。 从 16.2 开始,文档位于 node_modules/next/dist/docs/,项目的 AGENTS.md 会引用它。如果与本文档示例冲突,以已安装版本的文档为准。

标记:MUST — 不可违反;SHOULD — 默认同意,偏离需要理由。


1. 代码之前的决策

表格中的每个决策都要记录在 README(“决策”部分)或 ADR 中,并附上理由。未经记录理由而偏离默认值——不允许。

问题默认值何时改变
Next.js 还是 SPA如果需要至少一项:SSR/SEO、BFF(密钥、HttpOnly-cookie)、路由处理器,则使用 Next.js内部登录后应用,无需 SEO 和 BFF → 使用 Vite + React Router:构建和部署更简单
路由器App Router仅已有项目中使用 Pages Router
Monorepo否,单个应用第二个应用或包实际出现 → pnpm workspaces;Nx/Turborepo — 当构建或 CI 开始变慢时
Multi-Zones、微前端否独立团队,独立发布
服务器数据使用 Server Components 进行初始加载;使用 TanStack Query 进行交互式客户端数据和变更纯客户端应用 → 仅用 TanStack Query
文本与 i18n从第一天起就包含翻译模块(next-intl 或类似),即使只有一个语言环境,如果项目遵循 fsd-frontend“无需 i18n”的明确决策记录在 README 中
包管理器pnpm,版本在 packageManager 中—
部署立即决定:Vercel、Node 服务器(output: "standalone")或 Dockerenv、缓存、CI 都依赖于此

MUST: 不要“为将来”添加技术。Monorepo、第二个路由器、Storybook、状态管理器、MSW(作为“后端类型”)只有在有第一个实际消费者时才出现。


2. 步骤顺序

  1. 创建项目(pnpm create next-app@latest):TypeScript、ESLint、Tailwind、App Router。固定 packageManager、engines.node(Next 16 需要 Node 20.9+)和 .nvmrc。
  2. 立即删除生成器模板: 起始页面、public/ 中的 SVG、模板 README、演示样式。用 references/configs.md 中的骨架替换 README。留下“以后再用”的模板会一直存活到生产环境。不删除 create-next-app 的 AGENTS.md 和 CLAUDE.md:<!-- BEGIN:nextjs-agent-rules --> 和 <!-- END:nextjs-agent-rules --> 之间的块将代理指向已安装版本的文档,next dev 会自动维护它。自己的项目规则写在这些标记之外。
  3. 严格 TypeScript(references/configs.md 的第四部分)和 typecheck 脚本(tsc --noEmit)。
  4. 在 Next 之上的 FSD 结构(下面的第三部分)。
  5. Lint 和格式化: ESLint flat config(来自 eslint-config-next)+ 类型感知规则 + 边界 lint + Prettier。Next 16 移除了 next lint,并且在 next build 时不进行 lint——lint 作为独立脚本在 CI 中运行。
  6. Env 配置(第四部分)。
  7. 错误模型和 API 客户端 在 shared/api 中(第五部分)。
  8. _app 层中的提供器: QueryClient、主题、i18n、全局服务(toast、confirm)作为 shared 中的端口 + _app 中的实现。
  9. UI 基础(第六部分)。
  10. 测试: Vitest + Testing Library + MSW,使用 Playwright 进行 e2e(第七部分)。
  11. Git hooks: husky + lint-staged(eslint --fix, prettier)+ commitlint。
  12. CI: 每次 push 和 PR 时运行 lint、typecheck、test、build(第八部分)。
  13. 默认安全(第九部分)。
  14. 填写 README,反映实际情况(第十部分),并完成 Done 定义(第十一部分)。

步骤 1–3 作为一个单独的“scaffold”提交:这样在历史中就能看出生成器做了什么,以及你做了什么。


3. 在 Next 路由之上的 FSD

根据 FSD 官方指南针对 App Router:Next 的服务文件夹 app/ 在项目根目录,FSD 层在 src/ 中,而 app 和 pages 层加上 _ 前缀,以避免与 Next 的服务文件夹混淆。

app/                         Next 路由:仅限路由文件
├── layout.tsx               根布局 → 来自 src/_app 的 provider
├── (auth)/sign-in/page.tsx  export { SignInPage as default } from "@/_pages/sign-in"
└── api/auth/login/route.ts  路由处理器 (BFF),薄层
proxy.ts                     Next 16+(之前是 middleware.ts),与 app/ 同级
src/
├── _app/                    app 层:提供器、全局样式、服务实现
├── _pages/                  pages 层
├── widgets/                 (如果项目使用)
├── features/
├── entities/
└── shared/{ui,api,lib,config}

MUST:

  • app/ 中的文件要薄:从 src/_pages 重新导出页面、generateMetadata、解析 params/searchParams(在 Next 15+ 中是 Promise,需要 await)并通过 props 传递。文件中没有逻辑。
  • 路由处理器和 Server Actions 要薄:解析并验证输入 → 调用 src 中的函数 → 返回响应。每一个都是公共入口:自己检查授权,而不是依赖于 proxy.ts。
  • 不要创建 src/app 和 src/pages:Next 会在根目录和 src 中查找服务文件夹,同名文件夹很容易变成第二个路由器。
  • 边界 lint 了解前缀:src/_app、src/_pages/* 模式,而不是 src/app、src/pages/*(配置见 fsd-frontend、references/conventions.md,第十一部分)。
  • "use client" 尽可能放在树的下方。页面默认为服务器端,客户端组件是具有交互性的叶子节点。
  • 包含密钥的模块以 import "server-only" 开头,包含 window 的模块以 import "client-only" 开头。

详细说明和代码:references/next-structure.md。


4. 环境配置

MUST:

  • 变量在两个模块中读取:shared/config/env.server.ts(import "server-only")和 shared/config/env.client.ts。schema 使用 zod,导入时进行验证:配置错误在启动时而不是在第一个请求时失败。在其余代码中禁止使用 process.env(lint 规则)。
  • NEXT_PUBLIC_* 在构建时 嵌入到 bundle 中,并且仅当直接访问 process.env.NEXT_PUBLIC_X 时:不使用解构和 process.env[name]。无法为一个构建产物构建具有不同公共值的多个环境——此类值在服务器端读取并向下传递。
  • 密钥只能使用不带 NEXT_PUBLIC_ 前缀的变量。
  • .env.example 包含每个变量,带有注释和安全值;.env* 在 .gitignore 中,.env.example 除外。CI 中的构建使用 .env.example 中的值。

5. 错误模型和 API 客户端

MUST:

  • 错误在 shared/api 边界处规范化为带有 kind 的 AppError(模型见 fsd-frontend、references/conventions.md,第一部分)。在 shared/api 之外,没有人解析 Response、状态码或错误文本。
  • 在 fetch 之上构建一个 request()(或生成的客户端,同样包装):传递 signal,将网络错误转换为 network,HTTP 状态转换为 kind,对响应体进行 schema 验证。示例见 references/next-structure.md。
  • 错误类型由代码决定:状态码、extensions.code(GraphQL 对错误也返回 200)、响应体中的 code。如果后端只返回文本——在一个 mapper 中根据文本进行映射,并附上原因注释和测试。
  • 后端响应在边界处映射为领域类型;DTO 不会流入 UI。
  • 用户数据不会在用户之间缓存:对于依赖会话的响应,不使用 "use cache"/unstable_cache。
  • 如果存在 schema(OpenAPI、GraphQL),则根据 schema 生成客户端。schema 或生成的代码位于存储库中:CI 不应访问实时后端。

SHOULD: 传输层之上的接口(AuthApi + factory)——仅当已经有第二个消费者时(fsd-frontend、references/state-and-data.md,2.1)。不要引入 type: "mock" 的配置值,它会抛出“未实现”。


6. UI 基础

  • 设计令牌——:root 中的 CSS 变量(以及暗色主题),通过 @theme 连接到 Tailwind v4。组件中只使用令牌;原始 HEX 和任意值(text-[#3a3a3a])——作为一次性例外,并附上注释。
  • 类必须存在。 从 shadcn/ui 和示例中复制的组件带有自己的令牌(bg-card、text-muted-foreground)。要么引入这些令牌,要么替换这些类——否则组件会默默丢失样式。
  • shared/ui 原语基于无头库(Radix、React Aria)以实现可访问性;变体使用 cva,类拼接使用 cn(clsx + tailwind-merge)。
  • 字体使用 next/font,图片使用 next/image 并指定尺寸,images.remotePatterns 显式列出。
  • Storybook——仅当 UI 套件被多个应用或团队重用时才引入,不要太早。

7. 测试

  • Vitest + Testing Library + jsdom + MSW,配置 onUnhandledFrame: "error"(MSW 3;在 MSW 2 中为 onUnhandledRequest)。配置见 references/configs.md。
  • Vitest 无法渲染 async Server Components。将逻辑提取到函数中并进行单元测试,页面本身通过 e2e 测试。
  • Playwright 用于 3–10 个关键路径。在 CI 中,e2e 针对可预测的后端(mock 服务器、带有测试数据库的测试环境)运行,而不是针对通用环境,因为通用环境中测试会更改其他数据。
  • 第一个测试在第零天编写:它验证测试基础设施正常工作,并作为样本。

8. CI

MUST: 每次推送到主分支和每个 PR:lint、typecheck、test、build。GitHub Actions 模板见 references/configs.md。对于公共存储库,Actions 免费;对于私有存储库,有月度分钟配额。

  • CI 中的构建使用 .env.example,无需密钥。
  • e2e 作为单独的工作,当存在隔离的后端时执行;在此之前,在 README 中明确标注为什么 CI 中没有 e2e。
  • README 中的 CI 徽章与 workflow 同时出现。

9. 默认安全

  • poweredByHeader: false;通过 next.config.ts 中的 headers() 设置标头:X-Content-Type-Options: nosniff、Referrer-Policy: strict-origin-when-cross-origin、X-Frame-Options: DENY(或 CSP 中的 frame-ancestors)。带 nonce 的 CSP 是单独的任务,但解决方案(“有/没有”以及原因)会立即记录。
  • Server Actions 和路由处理器是公共端点:使用 schema 验证输入,并在每个端点中检查权限。
  • dangerouslySetInnerHTML——仅与 sanitizer 一起使用,并附上原因注释。
  • 不记录个人数据和令牌。
  • 授权——按照 frontend-auth-session。

10. README

骨架见 references/configs.md。一条规则:README 中只包含此提交中代码的真实情况。 每个部分在与描述代码相同的提交中更新。计划放在单独的“下一步”部分,并注明尚未完成。


11. 启动时的 Done 定义

  • 生成器模板已删除;README 是实际填充的骨架。
  • 已固定 packageManager、engines.node、.nvmrc。
  • TS strict;typecheck、lint、test、build 在本地通过(已运行,非假设)。
  • 带 _app/_pages 前缀的 FSD 布局;边界 lint 能捕获向上导入。
  • 环境变量通过带 schema 的两个模块定义;process.env 在其之外被 lint 禁止;.env.example 完整。
  • shared/api 中的 AppError 和 request() 已编写测试(网络状态、HTTP 状态、错误 schema)。
  • _app 中的提供器;服务器上 QueryClient 不是每个用户共享的。
  • 设计令牌作为 CSS 变量;所有使用的类都存在。
  • 已配置 Vitest + MSW + Playwright,各有一个有效的测试。
  • Git hooks 和 commitlint 正常工作。
  • CI 为绿色。
  • 安全标头和 poweredByHeader: false。
  • 第 1 部分的决策已记录。

12. 当怀疑时

  • 在“现在添加”和“需要时添加”之间——选择需要时添加。
  • 在“手动配置”和“保留 create-next-app 生成的内容”之间——保留,直到有理由更改,并在更改时记录原因。
  • 在“单个应用”和“monorepo”之间——选择单个应用。
  • 在“凭记忆的配置”和“来自当前版本文档的配置”之间——选择来自文档的配置。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

rbikbov/frontend-starter

Creates Architecture Decision Records documenting key technical decisions with context, alternatives considered, tradeoffs, consequences, and decision owners. Use when documenting "architecture decisions", "technical choices", "design decisions", or "ADRs".

rbikbov/frontend-starter

Проверка фронтенд-кода и документации на «нейрослоп» перед коммитом, PR или публикацией репозитория: остатки генераторов, мёртвые и недоделанные опции, утверждения в README и комментариях, не подтверждённые кодом, маркетинговый тон и эмодзи, лишние абстракции, хрупкая обработка ошибок, персональные данные в логах, несуществующие классы стилей. Использовать, когда просят проверить код или репозиторий «на слоп», подготовить проект к публикации или показу, сделать ревью кода, написанного с помощью ИИ, или перед тем как закоммитить собственную большую правку.

rbikbov/frontend-starter

Процесс разработки фичи с агентом: PRD с Non-Goals → компактная спецификация → задачи по одной на коммит → read-only исследование → tracer bullet → сборка с тестом сначала → независимое ревью субагентом → проверка в браузере. Использовать, когда просят сделать фичу, экран, пользовательский сценарий или заметное изменение поведения; когда нужно написать PRD, спецификацию или разбить работу на задачи; когда работа больше одного коммита. Не использовать для опечаток и однострочных правок.

rbikbov/frontend-starter

Авторизация и сессия во фронтенде на Next.js (App Router): где хранить токены, BFF на route handlers с HttpOnly-cookie, refresh токена без гонок, определение «не авторизован» (включая GraphQL, который отвечает 200), проверки в proxy.ts и Data Access Layer, безопасный редирект после входа, выход без утечки данных прошлого пользователя, токены в ссылках сброса пароля, формы входа и восстановления. Использовать, когда проектируешь или пишешь вход, регистрацию, восстановление пароля, защищённые страницы, API-клиент с refresh-токеном, или ревьюишь такой код.

相关技能