本教程面向具备React和TypeScript基础的前端开发者,系统讲解如何利用Claude Code CLI工具完成从项目脚手架搭建、组件架构设计、状态管理选型、API数据对接、样式系统构建、自动化测试到生产构建的完整前端工作流。学完后,你将掌握一条经过实战验证的Claude Code前端开发高效交付路径。
适用人群:有6个月以上React经验,想用AI工具提升前端开发效率的中高级开发者。
| 条件 | 说明 |
|---|---|
| Node.js | 20.x LTS 或更高版本 |
| 包管理器 | pnpm 9.x(推荐)或 npm 10.x |
| Claude Code | @anthropic-ai/claude-code 最新版 |
| React知识 | 函数组件、Hooks、基础TypeScript |
| 操作系统 | macOS / Linux / WSL2 |
确认Claude Code已就绪:
claude --version
# 预期输出: 1.0.x 或更高
用Vite创建React+TypeScript项目,这是目前最快的前端构建工具链:
pnpm create vite task-dashboard --template react-ts
cd task-dashboard
pnpm install
CLAUDE.md是Claude Code理解你项目的核心入口。一个专业的前端项目CLAUDE.md应该包含技术栈约定、目录规范和编码风格:
# Task Dashboard
## Tech Stack
- React 19 + TypeScript 5.6 (strict mode)
- Vite 6 for build tooling
- Tailwind CSS 4 for styling
- Zustand for client state
- TanStack Query v5 for server state
- React Router v7 for routing
- Vitest + React Testing Library for tests
## Project Structure
src/
├── components/ # 可复用UI组件(按功能分子目录)
│ ├── ui/ # 基础原子组件(Button, Input, Modal...)
│ ├── layout/ # 布局组件(Header, Sidebar, Footer...)
│ └── features/ # 业务功能组件(TaskList, TaskCard...)
├── hooks/ # 自定义Hooks
├── stores/ # Zustand stores
├── services/ # API调用层
├── types/ # TypeScript类型定义
├── utils/ # 工具函数
└── pages/ # 路由页面组件
## Code Conventions
- 组件用PascalCase命名,文件名用PascalCase.tsx
- Hooks用use前缀,文件名用camelCase.ts
- 优先使用named export,仅在页面组件用default export
- Props接口定义在组件文件内部,不单独建types文件(除非跨组件复用)
- 样式用Tailwind class,禁止内联style
- 所有组件必须包含TypeScript类型,禁止any
## Commands
- `pnpm dev` — 启动开发服务器
- `pnpm build` — 生产构建
- `pnpm test` — 运行测试
- `pnpm lint` — ESLint检查
- `pnpm type-check` — TypeScript类型检查
## Testing Rules
- 测试文件放在被测组件同级目录: Component.tsx → Component.test.tsx
- 用Vitest + React Testing Library
- 测试用户行为,不测试实现细节
- 每个组件至少覆盖: 渲染正确、用户交互、边界状态
在Claude Code中执行:
claude
进入交互模式后输入:
根据CLAUDE.md中的技术栈,安装所有需要的依赖包。包括:
Tailwind CSS 4, Zustand, TanStack Query v5, React Router v7, Vitest, React Testing Library, 以及它们的TypeScript类型定义。配置好tailwind和vitest。
Claude Code会自动执行以下操作(预期结果):
✓ 安装 tailwindcss @tailwindcss/vite zustand @tanstack/react-query react-router
✓ 安装 -D vitest @testing-library/react @testing-library/jest-dom jsdom
✓ 配置 vite.config.ts 集成 Tailwind 和 Vitest
✓ 创建 src/index.css 引入 Tailwind
✓ 配置 tsconfig.json 的 types 字段包含 vitest/globals
Q: Claude Code安装了错误版本的包
在CLAUDE.md中明确版本号,如 "zustand": "^5.0.0"。Claude Code会参考你指定的版本。
Q: Tailwind配置与Vite不兼容
Tailwind CSS v4使用@tailwindcss/vite插件,不再需要tailwind.config.js。确保Claude Code安装的是v4版本。
在Claude Code中建立组件架构时,采用原子设计(Atomic Design)方法论,让Claude Code按层级生成组件:
帮我创建一套UI基础原子组件,放在 src/components/ui/ 目录下。
需要以下组件,每个组件遵循以下规范:
1. 完整的TypeScript Props类型定义
2. 支持forwardRef
3. 支持className合并(用clsx)
4. 包含variants(用class-variance-authority)
5. 同目录下有对应的.test.tsx测试文件
组件列表:
- Button: primary/secondary/danger/ghost四种variant,sm/md/lg三种size
- Input: 支持label, error, disabled状态
- Badge: 支持不同颜色主题
- Card: 支持header/body/footer分区
- Modal: 支持打开/关闭动画,点击外部关闭
Claude Code生成的组件会遵循你的CLAUDE.md约定,输出类似:
// src/components/ui/Button.tsx
import { forwardRef } from 'react';
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/utils/cn';
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
danger: 'bg-red-600 text-white hover:bg-red-700',
ghost: 'hover:bg-gray-100 text-gray-700',
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4 text-sm',
lg: 'h-12 px-6 text-base',
},
},
defaultVariants: {
variant: 'primary',
size: 'md',
},
}
);
interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
}
);
Button.displayName = 'Button';
export { Button, buttonVariants };
export type { ButtonProps };
当需要一次性生成多个组件时,使用分批策略避免Claude Code上下文溢出:
第一批: 生成 Button, Input, Badge(基础表单组件)
第二批: 生成 Card, Modal, Dialog(容器组件)
第三批: 生成 DataTable, Pagination(复合组件)
每批生成后立即运行测试验证:
pnpm test src/components/ui/
Q: 生成的组件样式不一致 在CLAUDE.md中添加设计令牌(Design Tokens)章节,定义颜色、圆角、间距的统一规范。或者引入shadcn/ui作为基础组件库。
Q: 组件缺少边界case处理
追加提示词:请补充处理 loading、error、disabled、empty 四种状态的UI表现。
现代React应用推荐双层状态管理架构:
graph TB
subgraph Server["服务端状态层"]
A[React Query / TanStack Query] --> B[缓存管理]
A --> C[自动重新获取]
A --> D[乐观更新]
A --> E[轮询与分页]
end
subgraph Client["客户端状态层"]
F[Zustand Store] --> G[UI状态]
F --> H[用户偏好]
F --> I[表单临时数据]
F --> J[全局通知]
end
subgraph API["API调用层"]
K[fetch封装] --> L[请求拦截]
K --> M[响应处理]
K --> N[错误统一处理]
end
Server --> API
Client -.->|触发mutation| Server
在Claude Code中输入:
创建 src/services/api.ts,实现以下功能:
1. 基于fetch的HTTP客户端封装
2. 自动添加Content-Type: application/json
3. 统一错误处理,抛出自定义ApiError
4. 请求/响应拦截器模式
5. 支持请求取消(AbortController)
然后创建 src/services/taskService.ts,实现Task的CRUD:
- getTasks(filters?): GET /api/tasks
- getTaskById(id): GET /api/tasks/:id
- createTask(data): POST /api/tasks
- updateTask(id, data): PATCH /api/tasks/:id
- deleteTask(id): DELETE /api/tasks/:id
Task类型定义在 src/types/task.ts:
interface Task {
id: string;
title: string;
description?: string;
status: 'todo' | 'in_progress' | 'done';
priority: 'low' | 'medium' | 'high';
assignee?: string;
dueDate?: string;
createdAt: string;
updatedAt: string;
}
基于 taskService 创建 src/hooks/useTaskQueries.ts,使用 TanStack Query v5:
1. useTasks(filters?) - 查询任务列表,支持过滤参数
2. useTask(id) - 查询单个任务
3. useCreateTask() - 创建任务mutation,创建后自动刷新列表
4. useUpdateTask() - 更新任务mutation,乐观更新
5. useDeleteTask() - 删除任务mutation,删除后从缓存移除
要求:
- 所有query使用queryKey工厂模式
- createTask成功后使相关query失效
- updateTask使用乐观更新,失败时回滚
- deleteTask成功后从缓存移除该项
- 错误处理通过全局toast通知用户
Claude Code生成的queryKey工厂模式:
// src/hooks/useTaskQueries.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as taskService from '@/services/taskService';
import type { Task, CreateTaskInput, UpdateTaskInput } from '@/types/task';
// Query Key 工厂 — 集中管理缓存键
export const taskKeys = {
all: ['tasks'] as const,
lists: () => [...taskKeys.all, 'list'] as const,
list: (filters?: Record<string, unknown>) =>
[...taskKeys.lists(), filters] as const,
details: () => [...taskKeys.all, 'detail'] as const,
detail: (id: string) => [...taskKeys.details(), id] as const,
};
export function useTasks(filters?: Record<string, unknown>) {
return useQuery({
queryKey: taskKeys.list(filters),
queryFn: () => taskService.getTasks(filters),
});
}
export function useTask(id: string) {
return useQuery({
queryKey: taskKeys.detail(id),
queryFn: () => taskService.getTaskById(id),
enabled: !!id,
});
}
export function useCreateTask() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateTaskInput) => taskService.createTask(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: taskKeys.lists() });
},
});
}
export function useUpdateTask() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: UpdateTaskInput }) =>
taskService.updateTask(id, data),
onMutate: async ({ id, data }) => {
await queryClient.cancelQueries({ queryKey: taskKeys.detail(id) });
const previousTask = queryClient.getQueryData<Task>(taskKeys.detail(id));
queryClient.setQueryData(taskKeys.detail(id), (old: Task) => ({
...old,
...data,
}));
return { previousTask };
},
onError: (_err, { id }, context) => {
queryClient.setQueryData(taskKeys.detail(id), context?.previousTask);
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: taskKeys.lists() });
},
});
}
export function useDeleteTask() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => taskService.deleteTask(id),
onSuccess: (_data, deletedId) => {
queryClient.removeQueries({ queryKey: taskKeys.detail(deletedId) });
queryClient.invalidateQueries({ queryKey: taskKeys.lists() });
},
});
}
创建 src/stores/uiStore.ts,用Zustand管理:
1. sidebarOpen: boolean — 侧边栏展开/折叠
2. theme: 'light' | 'dark' — 主题切换
3. notifications: Notification[] — 全局通知队列
4. addNotification(message, type): 添加通知并3秒后自动移除
5. removeNotification(id): 手动移除通知
要求:
- 使用persist middleware持久化theme到localStorage
- 使用immer middleware支持不可变更新
- 导出独立的selector函数,避免不必要的re-render
Q: TanStack Query缓存键冲突
始终使用queryKey工厂模式(如上面的taskKeys),不要手写字符串数组。
Q: Zustand store导致频繁re-render 为每个状态切片导出独立的selector:
// 错误:订阅整个store
const { sidebarOpen, theme } = useUIStore();
// 正确:只订阅需要的状态
const sidebarOpen = useUIStore((s) => s.sidebarOpen);
const theme = useUIStore((s) => s.theme);
使用React Router v7配置以下路由,创建 src/router.tsx:
路由结构:
/ → DashboardPage(任务统计面板)
/tasks → TaskListPage(任务列表,支持筛选排序)
/tasks/:id → TaskDetailPage(任务详情)
/tasks/new → TaskFormPage(创建新任务)
/settings → SettingsPage(用户设置)
要求:
- 使用createBrowserRouter + RouterProvider
- 实现Lazy Loading(React.lazy + Suspense)
- 添加Layout组件包裹所有页面(Header + Sidebar + Main)
- 添加404页面兜底
- 添加全局Loading Spinner
// src/router.tsx
import { createBrowserRouter, Navigate } from 'react-router';
import { lazy, Suspense } from 'react';
import { Layout } from '@/components/layout/Layout';
import { LoadingSpinner } from '@/components/ui/LoadingSpinner';
const Lazy = (Component: React.LazyExoticComponent<React.ComponentType>) => (
<Suspense fallback={<LoadingSpinner />}>
<Component />
</Suspense>
);
export const router = createBrowserRouter([
{
element: <Layout />,
children: [
{ index: true, element: Lazy(lazy(() => import('@/pages/DashboardPage'))) },
{ path: 'tasks', element: Lazy(lazy(() => import('@/pages/TaskListPage'))) },
{ path: 'tasks/:id', element: Lazy(lazy(() => import('@/pages/TaskDetailPage'))) },
{ path: 'tasks/new', element: Lazy(lazy(() => import('@/pages/TaskFormPage'))) },
{ path: 'settings', element: Lazy(lazy(() => import('@/pages/SettingsPage'))) },
{ path: '404', element: Lazy(lazy(() => import('@/pages/NotFoundPage'))) },
{ path: '*', element: <Navigate to="/404" replace /> },
],
},
]);
以任务列表页为例,向Claude Code描述页面需求:
创建 src/pages/TaskListPage.tsx,实现一个任务管理列表页面:
功能:
1. 顶部搜索栏(实时过滤任务标题)
2. 状态筛选Tab(全部/待办/进行中/已完成)
3. 优先级下拉筛选
4. 任务卡片网格布局(响应式:移动端1列,平板2列,桌面3列)
5. 每张任务卡片显示:标题、优先级Badge、负责人头像、截止日期
6. 卡片点击跳转到详情页
7. 右下角浮动"新建任务"按钮
8. 空状态展示(无任务时显示引导插图)
9. 加载状态展示骨架屏
使用已有的 useTasks hook 获取数据。
使用已有的 UI 组件(Button, Input, Badge, Card)。
样式使用Tailwind CSS。
Q: 懒加载导致页面闪烁 为Suspense提供与页面结构一致的骨架屏fallback,而非简单的Loading文字。
Q: 路由守卫实现
在Layout组件中用useEffect检查认证状态,未登录时重定向到登录页。
在 src/index.css 中配置 Tailwind CSS v4 主题:
自定义设计令牌:
- 主色调: blue-600 (#2563EB)
- 成功色: green-500
- 警告色: amber-500
- 危险色: red-500
- 圆角: 默认8px, 大号12px
- 阴影: sm/md/lg三档
- 动画: 添加fade-in和slide-up两个自定义动画
字体:
- 中文: system-ui, -apple-system, "PingFang SC"
- 代码: "JetBrains Mono", monospace
Tailwind CSS v4使用CSS-first配置,预期输出:
/* src/index.css */
@import "tailwindcss";
@theme {
--color-primary: #2563EB;
--color-primary-hover: #1D4ED8;
--color-success: #22C55E;
--color-warning: #F59E0B;
--color-danger: #EF4444;
--radius-default: 8px;
--radius-lg: 12px;
--shadow-card: 0 1px 3px rgba(0, 0, 0, 0.1);
--shadow-elevated: 0 4px 12px rgba(0, 0, 0, 0.1);
--animate-fade-in: fade-in 0.2s ease-out;
--animate-slide-up: slide-up 0.3s ease-out;
--font-sans: system-ui, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
--font-mono: "JetBrains Mono", "Fira Code", monospace;
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slide-up {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
在CLAUDE.md中明确响应式策略,让Claude Code生成一致的响应式代码:
## Responsive Breakpoints
- sm: 640px (手机横屏)
- md: 768px (平板竖屏)
- lg: 1024px (平板横屏/小笔记本)
- xl: 1280px (桌面)
- 2xl: 1536px (大屏桌面)
策略: Mobile First,默认写移动端样式,用sm/md/lg/xl递增。
Q: Claude Code生成的Tailwind类名顺序混乱
安装prettier-plugin-tailwindcss,Claude Code通常会自动识别并遵循Prettier配置。
Q: 暗黑模式支持
在Tailwind主题中添加--dark-mode: class,并在Zustand store中管理主题状态,切换时给<html>添加dark类名。
Claude Code通常在第一步就会帮你配置好Vitest,但你需要明确测试策略。在CLAUDE.md中添加测试规范后,让Claude Code生成测试:
为 src/components/ui/Button.tsx 生成完整的测试文件 Button.test.tsx。
测试要求:
1. 渲染测试:正确渲染文本内容
2. Variant测试:四种variant都有正确的CSS类名
3. Size测试:三种size都有正确的CSS类名
4. 交互测试:点击事件正确触发
5. 禁用测试:disabled状态下不可点击
6. Ref转发测试:forwardRef正确工作
7. 类名合并测试:自定义className正确合并
使用 Vitest + React Testing Library。
不要使用已废弃的act()包装,用screen和userEvent。
// src/components/ui/Button.test.tsx
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './Button';
describe('Button', () => {
it('renders children text', () => {
render(<Button>Click me</Button>);
expect(screen.getByRole('button', { name: 'Click me' })).toBeInTheDocument();
});
it.each([
['primary', 'bg-blue-600'],
['secondary', 'bg-gray-100'],
['danger', 'bg-red-600'],
['ghost', 'hover:bg-gray-100'],
] as const)('applies %s variant styles', (variant, expectedClass) => {
render(<Button variant={variant}>{variant}</Button>);
const button = screen.getByRole('button');
expect(button.className).toContain(expectedClass);
});
it('calls onClick when clicked', async () => {
const onClick = vi.fn();
const user = userEvent.setup();
render(<Button onClick={onClick}>Click</Button>);
await user.click(screen.getByRole('button'));
expect(onClick).toHaveBeenCalledOnce();
});
it('does not call onClick when disabled', async () => {
const onClick = vi.fn();
const user = userEvent.setup();
render(<Button disabled onClick={onClick}>Disabled</Button>);
await user.click(screen.getByRole('button'));
expect(onClick).not.toHaveBeenCalled();
});
it('forwards ref to button element', () => {
const ref = { current: null };
render(<Button ref={ref}>Ref</Button>);
expect(ref.current).toBeInstanceOf(HTMLButtonElement);
});
it('merges custom className', () => {
render(<Button className="my-custom">Custom</Button>);
expect(screen.getByRole('button').className).toContain('my-custom');
});
});
为 src/hooks/useTaskQueries.ts 生成测试 useTaskQueries.test.ts。
要求:
1. Mock taskService的所有方法
2. 用 @tanstack/react-query 的 QueryClientWrapper 包裹
3. 测试 useTasks 成功获取数据
4. 测试 useCreateTask 成功后自动刷新列表
5. 测试 useUpdateTask 乐观更新和错误回滚
6. 测试 useDeleteTask 成功后移除缓存
7. 使用 waitFor 等待异步状态更新
pnpm test
如果测试失败,让Claude Code自动修复:
运行 pnpm test,修复所有失败的测试。不要修改测试用例的期望值,修改实现代码使其通过测试。
Q: 测试中TanStack Query报错 "No QueryClient set" 创建测试用的Wrapper:
function createQueryWrapper() {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
return function Wrapper({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
};
}
Q: 测试运行太慢
在vitest.config.ts中启用pool: 'forks'和poolOptions: { forks: { singleFork: true } }。
优化 vite.config.ts 的生产构建配置:
1. 手动分包策略(vendor chunks):
- react/react-dom 打一个包
- react-router 打一个包
- tanstack-query 打一个包
- zustand 打一个包
- UI组件打一个包
2. 开启 gzip 压缩报告
3. 图片资源优化(小于4kb内联,大于4kb生成文件)
4. 配置路径别名 @/ 映射到 src/
5. 配置开发代理 /api → http://localhost:3001
预期vite.config.ts:
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tailwindcss from '@tailwindcss/vite';
import { resolve } from 'path';
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
'@': resolve(__dirname, './src'),
},
},
server: {
proxy: {
'/api': {
target: 'http://localhost:3001',
changeOrigin: true,
},
},
},
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor-react': ['react', 'react-dom'],
'vendor-router': ['react-router'],
'vendor-query': ['@tanstack/react-query'],
'vendor-state': ['zustand'],
},
},
},
reportCompressedSize: true,
},
});
让Claude Code执行完整的部署前验证:
执行以下部署前检查并报告结果:
1. pnpm type-check — TypeScript类型检查,0错误
2. pnpm lint — ESLint检查,0警告
3. pnpm test — 全部测试通过
4. pnpm build — 构建成功
5. 分析构建产物大小,报告各chunk体积
6. 检查是否有未使用的依赖(depcheck)
配置部署到 Vercel:
1. 创建 vercel.json 配置SPA路由重写(所有路由→index.html)
2. 配置环境变量: VITE_API_BASE_URL
3. 输出构建命令和输出目录
预期vercel.json:
{
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }],
"buildCommand": "pnpm build",
"outputDirectory": "dist",
"env": {
"VITE_API_BASE_URL": "@api-base-url"
}
}
下面是一个完整的任务管理仪表盘项目,综合运用前面七步的所有技术。整体架构如下:
graph TB
subgraph Browser["浏览器"]
subgraph Router["React Router v7"]
RP[RouterProvider] --> Dash[DashboardPage]
RP --> TL[TaskListPage]
RP --> TD[TaskDetailPage]
RP --> TF[TaskFormPage]
RP --> Set[SettingsPage]
end
subgraph State["状态管理"]
RQ[TanStack Query<br/>服务端状态] --> Cache[缓存层]
ZS[Zustand<br/>客户端状态] --> UI[UI状态]
end
subgraph Components["组件层"]
UI_Comps[原子组件<br/>Button/Input/Badge] --> Feat_Comps[业务组件<br/>TaskCard/TaskList]
Feat_Comps --> Pages[页面组件]
end
end
subgraph Server["后端API"]
API["/api/tasks<br/>CRUD Endpoints"]
end
Pages --> State
State --> Services[API Service层]
Services -->|fetch| Server
| 文件路径 | 作用 | 行数估计 |
|---|---|---|
CLAUDE.md |
项目约定 | ~60行 |
src/types/task.ts |
Task类型定义 | ~20行 |
src/services/api.ts |
HTTP客户端封装 | ~80行 |
src/services/taskService.ts |
Task API调用 | ~50行 |
src/hooks/useTaskQueries.ts |
TanStack Query hooks | ~100行 |
src/stores/uiStore.ts |
UI状态管理 | ~60行 |
src/components/ui/*.tsx |
基础组件(5个) | ~400行 |
src/components/layout/*.tsx |
布局组件(3个) | ~200行 |
src/components/features/*.tsx |
业务组件(6个) | ~500行 |
src/pages/*.tsx |
页面组件(5个) | ~600行 |
src/router.tsx |
路由配置 | ~30行 |
| 总计 | ~2100行 |
按以下顺序向Claude Code发出指令,可以高效完成整个项目:
# Step 1 — 基础设施(5分钟)
"初始化项目,安装所有依赖,配置Tailwind、Vitest、路径别名"
# Step 2 — 类型与API层(10分钟)
"创建所有TypeScript类型定义和API Service层"
# Step 3 — 状态管理(10分钟)
"创建TanStack Query hooks和Zustand store"
# Step 4 — UI组件库(15分钟)
"生成所有原子组件,每个组件带完整测试"
# Step 5 — 布局组件(10分钟)
"生成Layout、Header、Sidebar布局组件"
# Step 6 — 业务组件(15分钟)
"生成TaskCard、TaskList、TaskForm、StatusFilter等业务组件"
# Step 7 — 页面组件(15分钟)
"生成所有页面组件并配置路由"
# Step 8 — 测试与优化(10分钟)
"运行全量测试,修复失败用例,分析构建产物大小"
总估计:约90分钟完成一个完整的前端项目。
完成后的项目应达到以下指标:
| 指标 | 目标值 |
|---|---|
| 首屏LCP | < 1.5s |
| FID | < 100ms |
| CLS | < 0.1 |
| 构建产物总大小 | < 200KB (gzip) |
| 测试覆盖率 | > 80% |
| TypeScript错误 | 0 |
| ESLint警告 | 0 |
安装shadcn/ui的Claude Code Skill后,可以直接用自然语言生成高质量的shadcn组件:
# 安装shadcn CLI
pnpm dlx shadcn@latest init
# 在Claude Code中使用
"用shadcn/ui的DataTable组件实现任务列表,支持排序、筛选和分页"
如果团队使用Figma,可以通过Figma MCP Server将设计稿直接转化为代码:
1. 安装Figma MCP Server
2. 在Claude Code中输入: "根据Figma文件 xxx 的设计稿,生成TaskCard组件"
3. Claude Code会读取Figma的设计令牌、布局和样式,生成匹配的React组件
对于已有的React项目,不要一次性重构。使用Claude Code的渐进式策略:
第一阶段: 只添加CLAUDE.md,让Claude Code理解项目现状
第二阶段: 让Claude Code为新功能编写代码(遵循现有模式)
第三阶段: 逐步让Claude Code重构旧代码(一次一个模块)
第四阶段: 引入新的工具链(Tailwind、Zustand等)
为 src/components/ui/ 下所有组件生成 Storybook stories 文件。
每个组件至少3个story: Default, WithVariants, EdgeCase。
使用CSF 3.0格式。
Claude Code擅长生成结构化代码,但对于复杂的拖拽、手势、动画交互,建议先写好交互逻辑的伪代码注释,再让Claude Code填充实现。
在CLAUDE.md中强制要求可访问性规范:
## Accessibility (Must Follow)
- 所有交互元素必须有aria-label
- 表单input必须关联label
- 颜色对比度至少4.5:1
- 键盘可操作(Tab/Enter/Escape)
- 使用role属性标注自定义组件
把团队的ESLint配置、Prettier配置、Git hooks都配置好后再使用Claude Code。这样Claude Code生成的代码会自动遵循团队规范。
flowchart LR
A[编写CLAUDE.md] --> B[项目初始化<br/>安装依赖]
B --> C[类型定义<br/>API层]
C --> D[状态管理<br/>Query+Store]
D --> E[UI组件库<br/>原子组件]
E --> F[布局+路由<br/>页面骨架]
F --> G[业务组件<br/>功能页面]
G --> H[测试+修复<br/>构建优化]
H --> I[部署上线]
style A fill:#2563EB,color:#fff
style I fill:#22C55E,color:#fff
| 评估维度 | 说明 |
|---|---|
| 适合训练营类型 | 前端工程师集训营、全栈开发训练营、AI辅助编程工作坊 |
| 学员基础要求 | 6个月以上React经验,了解TypeScript基础 |
| 预计教学时长 | 4-6小时(含实操练习) |
| 实验环境要求 | 每人一台开发机,安装好Claude Code和Node.js 20+ |
| 课程组织建议 | 上午讲解7步方法论(2h),下午实操完成Task Dashboard项目(3h),最后总结Review(1h) |
| 课后作业 | 将Task Dashboard扩展为完整的项目管理工具,添加看板视图和团队协作功能 |
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
