高级前端
用于 React/Next.js 应用的前端开发模式、性能优化和自动化工具。
目录
项目脚手架
使用 TypeScript、Tailwind CSS 和最佳实践配置生成新的 Next.js 或 React 项目。
工作流:创建新的前端项目
-
使用项目名称和模板运行脚手架工具:
python scripts/frontend_scaffolder.py my-app --template nextjs -
添加可选功能(auth, api, forms, testing, storybook):
python scripts/frontend_scaffolder.py dashboard --template nextjs --features auth,api -
进入项目目录并安装依赖:
cd my-app && npm install -
启动开发服务器:
npm run dev
脚手架选项
| 选项 | 描述 |
|---|---|
--template nextjs | Next.js 14+,使用 App Router 和 Server Components |
--template react | React + Vite,使用 TypeScript |
--features auth | 添加 NextAuth.js 身份验证 |
--features api | 添加 React Query + API 客户端 |
--features forms | 添加 React Hook Form + Zod 验证 |
--features testing | 添加 Vitest + Testing Library |
--dry-run | 预览文件而不实际创建 |
生成的项目结构(Next.js)
my-app/
├── app/
│ ├── layout.tsx # 根布局,包含字体
│ ├── page.tsx # 首页
│ ├── globals.css # Tailwind + CSS 变量
│ └── api/health/route.ts
├── components/
│ ├── ui/ # Button, Input, Card
│ └── layout/ # Header, Footer, Sidebar
├── hooks/ # useDebounce, useLocalStorage
├── lib/ # utils (cn), constants
├── types/ # TypeScript 接口
├── tailwind.config.ts
├── next.config.js
└── package.json
组件生成
生成包含 TypeScript 类型、测试文件和 Storybook 故事的 React 组件。
工作流:创建新组件
-
生成一个客户端组件:
python scripts/component_generator.py Button --dir src/components/ui -
生成一个服务端组件:
python scripts/component_generator.py ProductCard --type server -
生成包含测试和故事文件的组件:
python scripts/component_generator.py UserProfile --with-test --with-story -
生成自定义 Hook:
python scripts/component_generator.py FormValidation --type hook
生成器选项
| 选项 | 描述 |
|---|---|
--type client | 客户端组件,包含 'use client'(默认) |
--type server | 异步服务端组件 |
--type hook | 自定义 React Hook |
--with-test | 包含测试文件 |
--with-story | 包含 Storybook 故事 |
--flat | 直接在输出目录创建,不建子目录 |
--dry-run | 预览而不创建文件 |
生成的组件示例
'use client';
import { useState } from 'react';
import { cn } from '@/lib/utils';
interface ButtonProps {
className?: string;
children?: React.ReactNode;
}
export function Button({ className, children }: ButtonProps) {
return (
<div className={cn('', className)}>
{children}
</div>
);
}
打包分析
分析 package.json 和项目结构,寻找打包优化机会。
工作流:优化打包体积
-
针对你的项目运行分析器:
python scripts/bundle_analyzer.py /path/to/project -
查看健康评分和问题:
Bundle Health Score: 75/100 (C) HEAVY DEPENDENCIES: moment (290KB) Alternative: date-fns (12KB) or dayjs (2KB) lodash (71KB) Alternative: lodash-es with tree-shaking -
通过替换重型依赖来应用推荐的修复。
-
使用详细模式重新运行,以检查导入模式:
python scripts/bundle_analyzer.py . --verbose
打包评分解读
| 分数 | 等级 | 操作 |
|---|---|---|
| 90-100 | A | 打包优化良好 |
| 80-89 | B | 有轻微优化空间 |
| 70-79 | C | 需要替换重型依赖 |
| 60-69 | D | 多个问题需要关注 |
| 0-59 | F | 打包体积有严重问题 |
检测到的重型依赖
分析器会识别以下常见的重型包:
| 包 | 大小 | 替代方案 |
|---|---|---|
| moment | 290KB | date-fns (12KB) 或 dayjs (2KB) |
| lodash | 71KB | lodash-es (配合 tree-shaking) |
| axios | 14KB | 原生 fetch 或 ky (3KB) |
| jquery | 87KB | 原生 DOM API |
| @mui/material | 很大 | shadcn/ui 或 Radix UI |
React 模式
参考:references/react_patterns.md
复合组件
在相关组件之间共享状态:
const Tabs = ({ children }) => {
const [active, setActive] = useState(0);
return (
<TabsContext.Provider value={{ active, setActive }}>
{children}
</TabsContext.Provider>
);
};
Tabs.List = TabList;
Tabs.Panel = TabPanel;
// 使用
<Tabs>
<Tabs.List>
<Tabs.Tab>一</Tabs.Tab>
<Tabs.Tab>二</Tabs.Tab>
</Tabs.List>
<Tabs.Panel>内容 1</Tabs.Panel>
<Tabs.Panel>内容 2</Tabs.Panel>
</Tabs>
自定义 Hooks
提取可复用的逻辑:
function useDebounce<T>(value: T, delay = 500): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// 使用
const debouncedSearch = useDebounce(searchTerm, 300);
Render Props
共享渲染逻辑:
function DataFetcher({ url, render }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url).then(r => r.json()).then(setData).finally(() => setLoading(false));
}, [url]);
return render({ data, loading });
}
// 使用
<DataFetcher
url="/api/users"
render={({ data, loading }) =>
loading ? <Spinner /> : <UserList users={data} />
}
/>
Next.js 优化
参考:references/nextjs_optimization_guide.md
服务端组件 vs 客户端组件
默认使用服务端组件。仅在需要以下功能时添加 'use client':
- 事件处理(onClick, onChange)
- 状态管理(useState, useReducer)
- 副作用(useEffect)
- 浏览器 API
// 服务端组件(默认)- 不加 'use client'
async function ProductPage({ params }) {
const product = await getProduct(params.id); // 服务端请求
return (
<div>
<h1>{product.name}</h1>
<AddToCartButton productId={product.id} /> {/* 客户端组件 */}
</div>
);
}
// 客户端组件
'use client';
function AddToCartButton({ productId }) {
const [adding, setAdding] = useState(false);
return <button onClick={() => addToCart(productId)}>添加</button>;
}
图片优化
import Image from 'next/image';
// 首屏立即加载
<Image
src="/hero.jpg"
alt="英雄区"
width={1200}
height={600}
priority
/>
// 使用 fill 的响应式图片
<div className="relative aspect-video">
<Image
src="/product.jpg"
alt="产品"
fill
sizes="(max-width: 768px) 100vw, 50vw"
className="object-cover"
/>
</div>
数据获取模式
// 并行获取
async function Dashboard() {
const [user, stats] = await Promise.all([
getUser(),
getStats()
]);
return <div>...</div>;
}
// 使用 Suspense 实现流式渲染
async function ProductPage({ params }) {
return (
<div>
<ProductDetails id={params.id} />
<Suspense fallback={<ReviewsSkeleton />}>
<Reviews productId={params.id} />
</Suspense>
</div>
);
}
无障碍访问与测试
参考:references/frontend_best_practices.md
无障碍检查清单
- 语义化 HTML:使用适当的元素(
<button>,<nav>,<main>) - 键盘导航:所有交互元素应可聚焦
- ARIA 标签:为图标和复杂组件提供标签
- 颜色对比度:普通文本至少 4.5:1
- 焦点指示器:可见的焦点状态
// 无障碍按钮
<button
type="button"
aria-label="关闭对话框"
onClick={onClose}
className="focus-visible:ring-2 focus-visible:ring-blue-500"
>
<XIcon aria-hidden="true" />
</button>
// 键盘用户的跳过链接
<a href="#main-content" className="sr-only focus:not-sr-only">
跳到主内容
</a>
测试策略
// 使用 React Testing Library 的组件测试
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('点击按钮触发操作', async () => {
const onClick = vi.fn();
render(<Button onClick={onClick}>点击我</Button>);
await userEvent.click(screen.getByRole('button'));
expect(onClick).toHaveBeenCalledTimes(1);
});
// 测试无障碍
测试('对话框是无障碍的', async () => {
render(<Dialog open={true} title="确认" />);
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByRole('dialog')).toHaveAttribute('aria-labelledby');
});
快速参考
常用 Next.js 配置
// next.config.js
const nextConfig = {
images: {
remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }],
formats: ['image/avif', 'image/webp'],
},
experimental: {
optimizePackageImports: ['lucide-react', '@heroicons/react'],
},
};
Tailwind CSS 工具类
// 使用 cn() 实现条件样式
import { cn } from '@/lib/utils';
<button className={cn(
'px-4 py-2 rounded',
variant === 'primary' && 'bg-blue-500 text-white',
disabled && 'opacity-50 cursor-not-allowed'
)} />
TypeScript 模式
// 包含 children 的 Props
interface CardProps {
className?: string;
children: React.ReactNode;
}
// 泛型组件
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
}
function List<T>({ items, renderItem }: ListProps<T>) {
return <ul>{items.map(renderItem)}</ul>;
}
资源
- React 模式:
references/react_patterns.md - Next.js 优化:
references/nextjs_optimization_guide.md - 最佳实践:
references/frontend_best_practices.md - 追问库 (Matt Pocock grill):
references/forcing_questions.md - 组合映射(应 fork 给哪个专家):
references/composition_map.md
假设与可验证的成功标准(Karpathy 纪律)
在此技能搭建组件、推荐框架或审计打包体积之前,必须明确以下四个假设。
- 用户主要设备 + 网络 — mobile-4g, desktop-fiber, low-end-Android, 或 corporate-network。驱动所有性能决策。
- LCP 目标(毫秒) — 一个具体的数字,而非“快”。驱动打包预算和渲染选择。
- 是否依赖 SEO 或需要登录 — 驱动渲染模式(SSR/SSG/RSC vs. SPA)。
- WCAG 目标 + 指定的无障碍负责人 — AA, AAA, 或尽力而为。驱动无障碍投入和 CI 关口。
可验证的成功标准 (Karpathy #4) — 每项建议必须包含:
- 在主要设备上 p75 分位的 Core Web Vitals 目标 (LCP, INP, CLS)
- 每个路由的 JS 打包预算 (KB-gzip)
- Lighthouse 无障碍分数下限 + 性能分数下限
如果以上任何一项未声明,则该建议不完整——应返回追问库中的问题 2。
scripts/frontend_decision_engine.py 工具封装了这些检查:如果没有四个假设输入,它会拒绝推荐配置,并为匹配的配置打印可验证的阈值。
自定义配置
profiles/ 中的四个内置配置校准每项建议:
| 配置 | 何时选择 | LCP 目标 (mobile-4G p75) | 打包预算 |
|---|---|---|---|
next-app-router | SaaS 面向客户,需要 SEO + 动态内容,以 RSC 为先 | 2000ms | 150 KB-gzip / 路由 |
remix-or-sveltekit | 以移动端 4G 为主,以低 JS 为先,渐进增强 | 1500ms | 80 KB-gzip / 路由 |
vite-spa | 需要登录的应用,以桌面/公司网络为主 | 2500ms | 200 KB 初始化 + 80 KB / 路由 |
astro-or-static | 营销/文档/博客,接近零写入,SEO 关键 | 1200ms | 30 KB JS / 页面 |
通过以下命令选择配置:
python scripts/frontend_decision_engine.py \
--primary-device mobile-4g --lcp-target-ms 2000 \
--seo-dependent true --auth-walled false --team-size 5
该工具会返回最佳匹配的配置、备选方案(如果分数相差在 15% 以内)、技术栈选择、在该配置下应避免的反模式,以及所需的 CI 关口。
要添加自定义配置(例如,你所在组织的内部工具默认值):将 profiles/vite-spa.json 复制为 profiles/<your-org>.json,并调整 constraints 和 success_thresholds 参数。
组合映射
此技能不会重新实现由 POWERFUL 级别专家负责的范围。它会 fork 给它们。完整的路由表请参见 references/composition_map.md。关键分支:
| 关注点 | Fork 给 |
|---|---|
| WCAG 审计、对比度、屏幕阅读器 | engineering-team/skills/a11y-audit/ |
| 打包分析 + 运行时性能 | engineering/skills/performance-profiler/ |
| 电影 / 滚动讲述式着陆页 | engineering-team/skills/epic-design/ |
| Apple HIG (iOS / macOS / visionOS) | product-team/skills/apple-hig-expert/ |
| 预提交 Karpathy 审查 | engineering/karpathy-coder/ |
| 预研架构追问 | engineering/grill-me/ |
cs-frontend-engineer agent 通过 context: fork 来编排这些分支。可以从另一个 agent 中使用 Agent({subagent_type: "cs-frontend-engineer", prompt: "..."}) 来调用它,或者…
[为翻译而截断]