senior-frontend

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Senior Frontend Engineer

高级前端工程师

Overview

概述

Deliver production-grade frontend code following a structured three-phase workflow: context discovery, development, and handoff. This skill enforces strict quality standards including atomic design component architecture, comprehensive state management patterns, SSR/SSG/ISR optimization, and mandatory >85% test coverage with Vitest, React Testing Library, and Playwright.
Announce at start: "I'm using the senior-frontend skill for production-grade React/TypeScript development."

交付遵循上下文调研、开发、交付三阶段结构化工作流的生产级前端代码。本技能严格执行质量标准,包括原子设计组件架构、全面的状态管理模式、SSR/SSG/ISR优化,以及使用Vitest、React Testing Library和Playwright实现强制>85%的测试覆盖率。
启动时声明: "我正在使用senior-frontend技能进行生产级React/TypeScript开发。"

Phase 1: Context Discovery

第一阶段:上下文调研

Goal: Understand the existing codebase before writing any code.
目标: 在编写任何代码前先理解现有代码库。

Actions

执行动作

  1. Analyze existing codebase structure and conventions
  2. Identify the tech stack version (React 18/19, Next.js 14/15, TypeScript version)
  3. Review existing component library and design system
  4. Check state management approach already in use
  5. Understand build tooling and CI pipeline
  6. Map existing test infrastructure and coverage
  1. 分析现有代码库结构和规范
  2. 确认技术栈版本(React 18/19、Next.js 14/15、TypeScript版本)
  3. 梳理现有组件库和设计系统
  4. 检查当前已在使用的状态管理方案
  5. 了解构建工具和CI流水线
  6. 梳理现有测试基础设施和覆盖率情况

STOP — Do NOT proceed to Phase 2 until:

停止 — 满足以下条件前不得进入第二阶段:

  • Tech stack versions are identified
  • Existing patterns and conventions are documented
  • Test infrastructure is mapped
  • State management approach is identified

  • 已确认技术栈版本
  • 已记录现有模式和规范
  • 已梳理清楚测试基础设施
  • 已确认状态管理方案

Phase 2: Development

第二阶段:开发

Goal: Implement with strict TypeScript, atomic design, and TDD.
目标: 遵循严格的TypeScript规范、原子设计原则和测试驱动开发(TDD)实现需求。

Actions

执行动作

  1. Design component architecture following atomic design
  2. Implement with TypeScript strict mode
  3. Write tests alongside implementation (TDD when appropriate)
  4. Optimize for performance (bundle size, rendering, loading)
  5. Ensure accessibility compliance
  1. 遵循原子设计原则设计组件架构
  2. 开启TypeScript严格模式进行开发
  3. 实现功能的同时编写测试(合适场景下使用TDD)
  4. 进行性能优化(包体积、渲染、加载速度)
  5. 确保符合无障碍访问规范

Component Architecture Decision Table (Atomic Design)

组件架构决策表(原子设计)

LevelDescriptionBusiness LogicExample
AtomsSmallest building blocksNoneButton, Input, Icon, Badge
MoleculesComposed of atomsMinimalFormField, SearchBar, Card
OrganismsComplex with business logicYesDataTable, NavigationBar, CommentThread
TemplatesPage structure without dataLayout onlyDashboardLayout, AuthLayout
PagesTemplates connected to dataData fetchingUsersPage, SettingsPage
层级描述业务逻辑示例
原子(Atoms)最小的构建块Button、Input、Icon、Badge
分子(Molecules)由原子组合而成极简FormField、SearchBar、Card
有机体(Organisms)包含业务逻辑的复杂组件DataTable、NavigationBar、CommentThread
模板(Templates)不含数据的页面结构仅布局DashboardLayout、AuthLayout
页面(Pages)关联数据的模板数据获取UsersPage、SettingsPage

Atom Example

原子组件示例

typescript
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
  size?: 'sm' | 'md' | 'lg';
  isLoading?: boolean;
}

export function Button({ variant = 'primary', size = 'md', isLoading, children, ...props }: ButtonProps) {
  return (
    <button className={cn(buttonVariants({ variant, size }))} disabled={isLoading || props.disabled} {...props}>
      {isLoading ? <Spinner size={size} /> : children}
    </button>
  );
}
typescript
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
  size?: 'sm' | 'md' | 'lg';
  isLoading?: boolean;
}

export function Button({ variant = 'primary', size = 'md', isLoading, children, ...props }: ButtonProps) {
  return (
    <button className={cn(buttonVariants({ variant, size }))} disabled={isLoading || props.disabled} {...props}>
      {isLoading ? <Spinner size={size} /> : children}
    </button>
  );
}

State Management Decision Table

状态管理决策表

State TypeSolutionWhen to Use
Server stateReact Query / TanStack QueryAPI data, caching, sync
Form stateReact Hook Form + ZodForm validation, submission
Global UI stateZustandTheme, sidebar open, modals
Local UI stateuseState / useReducerComponent-specific state
URL statenuqs / useSearchParamsFilters, pagination, tabs
Complex localuseReducerMultiple related state transitions
Shared contextReact ContextTheme, locale, auth (infrequent updates)
状态类型解决方案使用场景
服务端状态React Query / TanStack QueryAPI数据、缓存、同步
表单状态React Hook Form + Zod表单校验、提交
全局UI状态Zustand主题、侧边栏开关、弹窗
本地UI状态useState / useReducer组件专属状态
URL状态nuqs / useSearchParams筛选、分页、标签页
复杂本地状态useReducer多个关联状态转换
共享上下文React Context主题、国际化、鉴权(低频率更新场景)

SSR / SSG / ISR Decision Table (Next.js App Router)

SSR / SSG / ISR 决策表(Next.js App Router)

PatternUse WhenCache Strategy
Static (SSG)Content rarely changesBuild time
ISRContent changes periodicallyRevalidate interval
SSRContent changes per requestNo cache
ClientUser-specific, interactiveBrowser
模式使用场景缓存策略
静态生成(SSG)内容极少变更构建时生成
增量静态再生成(ISR)内容定期更新按重验证间隔更新
服务端渲染(SSR)内容随每次请求变化不缓存
客户端渲染用户专属、高交互场景浏览器端渲染

Server vs Client Component Decision

服务端组件 vs 客户端组件决策

NeedComponent Type
Direct data fetchingServer (default)
Event handlers (onClick, onChange)Client (
'use client'
)
useState / useReducerClient
useEffect / useLayoutEffectClient
Browser APIs (window, localStorage)Client
Third-party libs using client featuresClient
No interactivity neededServer (default)
需求组件类型
直接获取数据服务端组件(默认)
事件处理(onClick、onChange)客户端组件(添加
'use client'
使用useState / useReducer客户端组件
使用useEffect / useLayoutEffect客户端组件
使用浏览器API(window、localStorage)客户端组件
依赖客户端特性的第三方库客户端组件
无需交互服务端组件(默认)

STOP — Do NOT proceed to Phase 3 until:

停止 — 满足以下条件前不得进入第三阶段:

  • Components follow atomic design hierarchy
  • TypeScript strict mode is enabled, no
    any
    types
  • Tests are written for all components
  • Accessibility is verified (axe-core)

  • 组件符合原子设计层级规范
  • 已开启TypeScript严格模式,无
    any
    类型
  • 所有组件都已编写测试
  • 已通过无障碍访问校验(axe-core)

Phase 3: Handoff

第三阶段:交付

Goal: Verify quality gates and prepare for review.
目标: 验证质量门禁,准备代码评审。

Actions

执行动作

  1. Verify test coverage meets >85% threshold
  2. Run full lint and type check
  3. Document complex components with JSDoc/TSDoc
  4. Create Storybook stories for UI components
  5. Performance audit (Lighthouse, bundle analysis)
  1. 验证测试覆盖率达到>85%的阈值
  2. 运行完整的代码检查和类型校验
  3. 使用JSDoc/TSDoc为复杂组件编写文档
  4. 为UI组件创建Storybook stories
  5. 性能审计(Lighthouse、包体积分析)

Performance Checklist

性能检查清单

  • Bundle size < 200KB gzipped (initial load)
  • Largest Contentful Paint < 2.5s
  • First Input Delay < 100ms
  • Cumulative Layout Shift < 0.1
  • Images: next/image with proper sizing and formats
  • Fonts: next/font with display swap
  • No layout thrashing (batch DOM reads/writes)
  • Virtualization for lists > 100 items
  • gzip压缩后初始加载包体积 < 200KB
  • 最大内容绘制(LCP) < 2.5s
  • 首次输入延迟(FID) < 100ms
  • 累积布局偏移(CLS) < 0.1
  • 图片:使用next/image,配置正确的尺寸和格式
  • 字体:使用next/font,配置display swap
  • 无布局抖动(批量处理DOM读写)
  • 超过100项的列表使用虚拟滚动

Coverage Thresholds

覆盖率阈值配置

json
{
  "coverageThreshold": {
    "global": {
      "branches": 85,
      "functions": 85,
      "lines": 85,
      "statements": 85
    }
  }
}
json
{
  "coverageThreshold": {
    "global": {
      "branches": 85,
      "functions": 85,
      "lines": 85,
      "statements": 85
    }
  }
}

STOP — Handoff complete when:

停止 — 满足以下条件则交付完成:

  • Test coverage >85% verified
  • Lint and type check pass with zero errors
  • Performance audit completed
  • Complex components documented

  • 已验证测试覆盖率>85%
  • 代码检查和类型校验零错误通过
  • 已完成性能审计
  • 复杂组件已编写文档

Testing Requirements

测试要求

Unit Tests (Vitest + React Testing Library)

单元测试(Vitest + React Testing Library)

typescript
describe('Button', () => {
  it('renders children', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByRole('button', { name: 'Click me' })).toBeInTheDocument();
  });

  it('shows loading state', () => {
    render(<Button isLoading>Click me</Button>);
    expect(screen.getByRole('button')).toBeDisabled();
  });

  it('calls onClick when clicked', async () => {
    const onClick = vi.fn();
    render(<Button onClick={onClick}>Click me</Button>);
    await userEvent.click(screen.getByRole('button'));
    expect(onClick).toHaveBeenCalledOnce();
  });
});
typescript
describe('Button', () => {
  it('renders children', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByRole('button', { name: 'Click me' })).toBeInTheDocument();
  });

  it('shows loading state', () => {
    render(<Button isLoading>Click me</Button>);
    expect(screen.getByRole('button')).toBeDisabled();
  });

  it('calls onClick when clicked', async () => {
    const onClick = vi.fn();
    render(<Button onClick={onClick}>Click me</Button>);
    await userEvent.click(screen.getByRole('button'));
    expect(onClick).toHaveBeenCalledOnce();
  });
});

Integration Tests

集成测试

  • Component compositions (form submission flow)
  • Data fetching with MSW (Mock Service Worker)
  • Routing and navigation
  • Error boundaries and fallbacks
  • 组件组合测试(表单提交流程)
  • 使用MSW(Mock Service Worker)模拟数据获取
  • 路由和导航测试
  • 错误边界和降级方案测试

E2E Tests (Playwright)

E2E测试(Playwright)

typescript
test('user can complete checkout', async ({ page }) => {
  await page.goto('/products');
  await page.getByRole('button', { name: 'Add to cart' }).first().click();
  await page.getByRole('link', { name: 'Cart' }).click();
  await expect(page.getByText('1 item')).toBeVisible();
  await page.getByRole('button', { name: 'Checkout' }).click();
});

typescript
test('user can complete checkout', async ({ page }) => {
  await page.goto('/products');
  await page.getByRole('button', { name: 'Add to cart' }).first().click();
  await page.getByRole('link', { name: 'Cart' }).click();
  await expect(page.getByText('1 item')).toBeVisible();
  await page.getByRole('button', { name: 'Checkout' }).click();
});

React Query Patterns

React Query 模式

typescript
function useUsers(filters: UserFilters) {
  return useQuery({
    queryKey: ['users', filters],
    queryFn: () => fetchUsers(filters),
    staleTime: 5 * 60 * 1000,
    placeholderData: keepPreviousData,
  });
}

function useUpdateUser() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: updateUser,
    onMutate: async (newUser) => {
      await queryClient.cancelQueries({ queryKey: ['users'] });
      const previous = queryClient.getQueryData(['users']);
      queryClient.setQueryData(['users'], (old) =>
        old.map(u => u.id === newUser.id ? { ...u, ...newUser } : u)
      );
      return { previous };
    },
    onError: (err, newUser, context) => {
      queryClient.setQueryData(['users'], context.previous);
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['users'] });
    },
  });
}

typescript
function useUsers(filters: UserFilters) {
  return useQuery({
    queryKey: ['users', filters],
    queryFn: () => fetchUsers(filters),
    staleTime: 5 * 60 * 1000,
    placeholderData: keepPreviousData,
  });
}

function useUpdateUser() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: updateUser,
    onMutate: async (newUser) => {
      await queryClient.cancelQueries({ queryKey: ['users'] });
      const previous = queryClient.getQueryData(['users']);
      queryClient.setQueryData(['users'], (old) =>
        old.map(u => u.id === newUser.id ? { ...u, ...newUser } : u)
      );
      return { previous };
    },
    onError: (err, newUser, context) => {
      queryClient.setQueryData(['users'], context.previous);
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['users'] });
    },
  });
}

Memoization Decision Table

缓存决策表

TechniqueUse WhenDo NOT Use When
useMemo
Expensive computation, referential equality for depsSimple calculations, primitive values
useCallback
Functions passed to memoized childrenFunctions not passed as props
React.memo
Component re-renders often with same propsProps change on every render
NoneDefault — do not memoizeAlways profile first

技术方案使用场景禁止使用场景
useMemo
计算成本高的逻辑、依赖需要引用相等的场景简单计算、原始值类型
useCallback
传递给缓存子组件的函数不作为props传递的函数
React.memo
相同props下频繁重渲染的组件每次渲染props都会变化的组件
默认场景 — 不要过度缓存永远先做性能分析再决定是否缓存

Anti-Patterns / Common Mistakes

反模式 / 常见错误

Anti-PatternWhy It Is WrongCorrect Approach
useEffect
for data fetching
Race conditions, no caching, no dedupReact Query or Server Components
Prop drilling more than 2 levelsTight coupling, maintenance burdenComposition, context, or Zustand
Business logic in componentsUntestable, unreusableExtract to hooks or utility functions
Barrel exportsBreaks tree-shaking, slower buildsDirect imports
Testing implementation detailsBrittle tests that break on refactorTest behavior: user actions and outcomes
any
type anywhere
Defeats TypeScript's purpose
unknown
+ type guards
Inline styles for non-dynamic valuesInconsistent, hard to maintainCSS modules, Tailwind, or styled-components
Memoizing everythingAdds complexity, often slowerProfile first, memoize second

反模式错误原因正确做法
useEffect
做数据获取
竞态条件、无缓存、无重复请求去重使用React Query或服务端组件
属性透传超过2层耦合度高、维护成本高使用组件组合、上下文或者Zustand
业务逻辑写在组件内不可测试、不可复用抽离到hooks或者工具函数中
桶导出(Barrel exports)破坏tree-shaking、构建变慢直接导入
测试实现细节测试脆弱,重构时容易失效测试行为:用户操作和输出结果
任意位置使用
any
类型
失去TypeScript的类型保护作用使用
unknown
+ 类型守卫
非动态值使用内联样式不一致、难维护使用CSS modules、Tailwind或者styled-components
所有内容都加缓存增加复杂度,往往反而更慢先做性能分析,再按需缓存

Documentation Lookup (Context7)

文档查询(Context7)

Use
mcp__context7__resolve-library-id
then
mcp__context7__query-docs
for up-to-date docs. Returned docs override memorized knowledge.
  • react
    — when uncertain about hooks API, component lifecycle, or React 19+ features
  • next.js
    — for App Router, Server Components, or Next.js-specific APIs
  • typescript
    — for advanced type patterns or compiler options
  • tailwindcss
    — for utility classes, configuration, or plugin API
  • vitest
    — for test runner API, matchers, or mock utilities

先使用
mcp__context7__resolve-library-id
再使用
mcp__context7__query-docs
获取最新文档,返回的文档优先级高于记忆中的知识。
  • react
    — 不确定hooks API、组件生命周期或者React 19+新特性时查询
  • next.js
    — 查询App Router、服务端组件或者Next.js专属API
  • typescript
    — 查询高级类型模式或者编译器选项
  • tailwindcss
    — 查询工具类、配置或者插件API
  • vitest
    — 查询测试运行器API、断言方法或者mock工具

Integration Points

集成点

SkillRelationship
testing-strategy
Strategy defines frontend test frameworks
test-driven-development
Components are built with TDD cycle
react-best-practices
Detailed React patterns complement this skill
performance-optimization
Frontend performance follows optimization methodology
code-review
Review verifies component architecture and test coverage
clean-code
Code quality principles apply to component code
webapp-testing
Playwright E2E tests use this skill's page structure
acceptance-testing
UI acceptance criteria drive component tests

技能关联关系
testing-strategy
测试策略定义前端测试框架选型
test-driven-development
组件遵循TDD循环开发
react-best-practices
详细的React模式是本技能的补充
performance-optimization
前端性能遵循通用优化方法论
code-review
代码评审验证组件架构和测试覆盖率
clean-code
组件代码遵循简洁代码质量原则
webapp-testing
Playwright E2E测试基于本技能的页面结构
acceptance-testing
UI验收标准驱动组件测试编写

Key Principles

核心原则

  • TypeScript strict mode, no
    any
    (use
    unknown
    + type guards)
  • Prefer composition over inheritance
  • Colocate tests, styles, and stories with components
  • Server Components by default; Client Components only when required
  • Error boundaries at route and feature boundaries
  • Accessibility is not optional (test with axe-core)

  • 开启TypeScript严格模式,禁止使用
    any
    (使用
    unknown
    + 类型守卫)
  • 优先使用组合而非继承
  • 测试、样式和stories与组件同位置存放
  • 默认使用服务端组件;仅在必要时使用客户端组件
  • 路由和功能边界设置错误边界
  • 无障碍访问是强制要求(使用axe-core测试)

Skill Type

技能类型

FLEXIBLE — Adapt component architecture and state management to the existing project conventions. The three-phase workflow is strongly recommended. Test coverage must target >85%. TypeScript strict mode is non-negotiable.
灵活适配 — 可根据现有项目规范调整组件架构和状态管理方案。强烈推荐遵循三阶段工作流。测试覆盖率必须达标>85%。TypeScript严格模式为强制要求,不可妥协。