关于 senior-frontend
senior-frontend 是面向 React 和 Next.js 开发者的前端技能,涵盖应用构建与审查。它结合项目和组件生成器、包体积分析、优化建议、无障碍检查及测试实践。
主要功能
- 01React 和 Next.js 项目脚手架
- 02生成 TypeScript 组件和 Hook
- 03包体积分析与建议
- 04React 和 Next.js 模式指导
- 05无障碍与测试清单
适用场景
- 01搭建 React 或 Next.js 应用
- 02生成带测试或 Storybook 的组件
- 03查找项目中的大型依赖
- 04检查无障碍设计和前端测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ sickn33/ agentic-awesome-skills --skill senior-frontend安装后在 Claude Code 中输入/senior-frontend确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/frontend_best_practices.mdnextjs_optimization_guide.mdreact_patterns.mdscripts/component_generator.pybundle_analyzer.pyfrontend_scaffolder.py详细介绍
高级前端
React/Next.js 应用的前端开发模式、性能优化和自动化工具。
适用场景
- 使用 TypeScript 和 Tailwind CSS 搭建新的 React 或 Next.js 项目时。
- 生成新组件或自定义 Hook 时。
- 分析和优化前端应用的打包体积时。
- 实现或审查 Compound Components、Render Props 等高级 React 模式时。
- 确保符合无障碍标准并实施完善的测试策略时。
目录
项目搭建
使用 TypeScript、Tailwind CSS 和最佳实践配置,生成新的 Next.js 或 React 项目。
工作流:创建新的前端项目
-
使用项目名称和模板运行脚手架工具:
python scripts/frontend_scaffolder.py my-app --template nextjs -
添加可选功能(身份验证、API、表单、测试、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 # Root layout with fonts
│ ├── page.tsx # Home page
│ ├── globals.css # Tailwind + CSS variables
│ └── api/health/route.ts
├── components/
│ ├── ui/ # Button, Input, Card
│ └── layout/ # Header, Footer, Sidebar
├── hooks/ # useDebounce, useLocalStorage
├── lib/ # utils (cn), constants
├── types/ # TypeScript interfaces
├── 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 | 使用 tree-shaking 的 lodash-es |
| 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;
// Usage
<Tabs>
<Tabs.List>
<Tabs.Tab>One</Tabs.Tab>
<Tabs.Tab>Two</Tabs.Tab>
</Tabs.List>
<Tabs.Panel>Content 1</Tabs.Panel>
<Tabs.Panel>Content 2</Tabs.Panel>
</Tabs>;
自定义 Hook
提取可复用逻辑:
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;
}
// Usage
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 });
}
// Usage
<DataFetcher
url="/api/users"
render={({ data, loading }) =>
loading ? <Spinner /> : <UserList users={data} />
}
/>;
Next.js 优化
参考:references/nextjs_optimization_guide.md
服务端组件与客户端组件
默认使用服务端组件。仅在需要以下功能时添加 'use client':
- 事件处理程序(onClick、onChange)
- 状态(useState、useReducer)
- 副作用(useEffect)
- 浏览器 API
// Server Component (default) - no 'use client'
async function ProductPage({ params }) {
const product = await getProduct(params.id); // Server-side fetch
return (
<div>
<h1>{product.name}</h1>
<AddToCartButton productId={product.id} /> {/* Client component */}
</div>
);
}
// Client Component
"use client";
function AddToCartButton({ productId }) {
const [adding, setAdding] = useState(false);
return <button onClick={() => addToCart(productId)}>Add</button>;
}
图像优化
import Image from 'next/image';
// Above the fold - load immediately
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority
/>
// Responsive image with fill
<div className="relative aspect-video">
<Image
src="/product.jpg"
alt="Product"
fill
sizes="(max-width: 768px) 100vw, 50vw"
className="object-cover"
/>
</div>
数据获取模式
// Parallel fetching
async function Dashboard() {
const [user, stats] = await Promise.all([getUser(), getStats()]);
return <div>...</div>;
}
// Streaming with 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
- 焦点指示器:焦点状态清晰可见
// Accessible button
<button
type="button"
aria-label="Close dialog"
onClick={onClose}
className="focus-visible:ring-2 focus-visible:ring-blue-500"
>
<XIcon aria-hidden="true" />
</button>
// Skip link for keyboard users
<a href="#main-content" className="sr-only focus:not-sr-only">
Skip to main content
</a>
测试策略
// Component test with React Testing Library
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
test("button triggers action on click", async () => {
const onClick = vi.fn();
render(<Button onClick={onClick}>Click me</Button>);
await userEvent.click(screen.getByRole("button"));
expect(onClick).toHaveBeenCalledTimes(1);
});
// Test accessibility
test("dialog is accessible", async () => {
render(<Dialog open={true} title="Confirm" />);
expect(screen.getByRole("dialog")).toBeInTheDocument();
expect(screen.getByRole("dialog")).toHaveAttribute("aria-labelledby");
});
快速参考
常见 Next.js 配置
// next.config.js
const nextConfig = {
images: {
remotePatterns: [{ hostname: "cdn.example.com" }],
formats: ["image/avif", "image/webp"],
},
experimental: {
optimizePackageImports: ["lucide-react", "@heroicons/react"],
},
};
Tailwind CSS 工具类
// Conditional classes with 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 模式
// Props with children
interface CardProps {
className?: string;
children: React.ReactNode;
}
// Generic component
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
限制
- 仅当任务明确符合上述范围时,才使用此技能。
- 不要将输出视为环境特定验证、测试或专家审查的替代品。
- 如果缺少必需的输入、权限、安全边界或成功标准,请停止并请求澄清。
快照限制
示例仅为摘录,不代表通过生产环境认证。脚手架依赖面向历史版本 Next14/React18/Tailwind3,安装前需要制定受支持且已修补的依赖方案。可选脚手架功能模板并不完整,目前会拒绝生成。生成的 React/Vite 配置需要匹配的别名、TSX 和 lint 设置;身份验证需要由服务器强制执行,而不能依赖前端 HOC。组件/测试假设应用已配置相关导入、样式和测试固定数据。软件包体积评分和 KB 表格仅为参考性启发指标,并非实测结果,也不能作为自动替换软件包的依据。
客户端组件可以在服务器上预渲染:localStorage 初始化程序可能导致水合不匹配;应在挂载后读取,并设置加载边界和处理错误/键变更。useAsync/DataFetcher 示例需要加入取消、过期响应和错误处理。自定义 select/dialog 示例未涵盖完整的键盘操作、焦点恢复和背景 inert 行为;请优先使用经过测试的基础组件。不要在 localStorage 中持久化承载者令牌,退出登录时清除会话数据,并在 API 路由中强制执行授权。没有按用户/租户划分的键时,切勿共享个性化缓存数据。请根据已安装的 Next 版本匹配 params、fetch 缓存、revalidateTag、Image preload 和动态 SSR API。