senior-frontend

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Senior Frontend

高级前端开发

Frontend development patterns, performance optimization, and automation tools for React/Next.js applications.
适用于React/Next.js应用的前端开发模式、性能优化与自动化工具。

Table of Contents

目录

Project Scaffolding

项目搭建

Generate a new Next.js or React project with TypeScript, Tailwind CSS, and best practice configurations.
生成一个包含TypeScript、Tailwind CSS和最佳实践配置的新Next.js或React项目。

Workflow: Create New Frontend Project

工作流:创建新前端项目

  1. Run the scaffolder with your project name and template:
    bash
    python scripts/frontend_scaffolder.py my-app --template nextjs
  2. Add optional features (auth, api, forms, testing, storybook):
    bash
    python scripts/frontend_scaffolder.py dashboard --template nextjs --features auth,api
  3. Navigate to the project and install dependencies:
    bash
    cd my-app && npm install
  4. Start the development server:
    bash
    npm run dev
  1. 使用项目名称和模板运行搭建脚本:
    bash
    python scripts/frontend_scaffolder.py my-app --template nextjs
  2. 添加可选功能(认证、API、表单、测试、Storybook):
    bash
    python scripts/frontend_scaffolder.py dashboard --template nextjs --features auth,api
  3. 进入项目目录并安装依赖:
    bash
    cd my-app && npm install
  4. 启动开发服务器:
    bash
    npm run dev

Scaffolder Options

搭建工具选项

OptionDescription
--template nextjs
Next.js 14+ with App Router and Server Components
--template react
React + Vite with TypeScript
--features auth
Add NextAuth.js authentication
--features api
Add React Query + API client
--features forms
Add React Hook Form + Zod validation
--features testing
Add Vitest + Testing Library
--dry-run
Preview files without creating them
选项描述
--template nextjs
带有App Router和Server Components的Next.js 14+
--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
预览文件而不实际创建

Generated Structure (Next.js)

生成的项目结构(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

my-app/
├── app/
│   ├── layout.tsx        # 包含字体的根布局
│   ├── page.tsx          # 首页
│   ├── globals.css       # Tailwind + CSS变量
│   └── api/health/route.ts
├── components/
│   ├── ui/               # 按钮、输入框、卡片
│   └── layout/           # 头部、底部、侧边栏
├── hooks/                # useDebounce、useLocalStorage
├── lib/                  # 工具函数(cn)、常量
├── types/                # TypeScript接口
├── tailwind.config.ts
├── next.config.js
└── package.json

Component Generation

组件生成

Generate React components with TypeScript, tests, and Storybook stories.
生成带有TypeScript、测试用例和Storybook故事的React组件。

Workflow: Create a New Component

工作流:创建新组件

  1. Generate a client component:
    bash
    python scripts/component_generator.py Button --dir src/components/ui
  2. Generate a server component:
    bash
    python scripts/component_generator.py ProductCard --type server
  3. Generate with test and story files:
    bash
    python scripts/component_generator.py UserProfile --with-test --with-story
  4. Generate a custom hook:
    bash
    python scripts/component_generator.py FormValidation --type hook
  1. 生成客户端组件:
    bash
    python scripts/component_generator.py Button --dir src/components/ui
  2. 生成服务器组件:
    bash
    python scripts/component_generator.py ProductCard --type server
  3. 生成包含测试和故事文件的组件:
    bash
    python scripts/component_generator.py UserProfile --with-test --with-story
  4. 生成自定义Hook:
    bash
    python scripts/component_generator.py FormValidation --type hook

Generator Options

生成工具选项

OptionDescription
--type client
Client component with 'use client' (default)
--type server
Async server component
--type hook
Custom React hook
--with-test
Include test file
--with-story
Include Storybook story
--flat
Create in output dir without subdirectory
--dry-run
Preview without creating files
选项描述
--type client
带有'use client'的客户端组件(默认)
--type server
异步服务器组件
--type hook
自定义React Hook
--with-test
包含测试文件
--with-story
包含Storybook故事文件
--flat
在输出目录直接创建,不生成子目录
--dry-run
预览文件而不实际创建

Generated Component Example

生成的组件示例

tsx
'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>
  );
}

tsx
'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>
  );
}

Bundle Analysis

包分析

Analyze package.json and project structure for bundle optimization opportunities.
分析package.json和项目结构,寻找包优化的机会。

Workflow: Optimize Bundle Size

工作流:优化包大小

  1. Run the analyzer on your project:
    bash
    python scripts/bundle_analyzer.py /path/to/project
  2. Review the health score and issues:
    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
  3. Apply the recommended fixes by replacing heavy dependencies.
  4. Re-run with verbose mode to check import patterns:
    bash
    python scripts/bundle_analyzer.py . --verbose
  1. 在项目上运行分析脚本:
    bash
    python scripts/bundle_analyzer.py /path/to/project
  2. 查看健康评分和问题:
    包健康评分:75/100(C级)
    
    大型依赖:
      moment (290KB)
        替代方案:date-fns (12KB) 或 dayjs (2KB)
    
      lodash (71KB)
        替代方案:支持摇树优化的lodash-es
  3. 应用推荐的修复方案,替换大型依赖。
  4. 启用详细模式重新运行,检查导入模式:
    bash
    python scripts/bundle_analyzer.py . --verbose

Bundle Score Interpretation

包评分解读

ScoreGradeAction
90-100ABundle is well-optimized
80-89BMinor optimizations available
70-79CReplace heavy dependencies
60-69DMultiple issues need attention
0-59FCritical bundle size problems
评分等级操作建议
90-100A包已优化到位
80-89B可进行小幅优化
70-79C替换大型依赖
60-69D需关注多个问题
0-59F存在严重的包大小问题

Heavy Dependencies Detected

检测到的大型依赖

The analyzer identifies these common heavy packages:
PackageSizeAlternative
moment290KBdate-fns (12KB) or dayjs (2KB)
lodash71KBlodash-es with tree-shaking
axios14KBNative fetch or ky (3KB)
jquery87KBNative DOM APIs
@mui/materialLargeshadcn/ui or Radix UI

分析工具会识别这些常见的大型包:
包名大小替代方案
moment290KBdate-fns (12KB) 或 dayjs (2KB)
lodash71KB支持摇树优化的lodash-es
axios14KB原生fetch 或 ky (3KB)
jquery87KB原生DOM API
@mui/material体积大shadcn/ui 或 Radix UI

React Patterns

React模式

Reference:
references/react_patterns.md
参考:
references/react_patterns.md

Compound Components

复合组件

Share state between related components:
tsx
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>
在相关组件之间共享状态:
tsx
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>

Custom Hooks

自定义Hook

Extract reusable logic:
tsx
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);
提取可复用逻辑:
tsx
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

渲染属性

Share rendering logic:
tsx
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} />
  }
/>

共享渲染逻辑:
tsx
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 Optimization

Next.js优化

Reference:
references/nextjs_optimization_guide.md
参考:
references/nextjs_optimization_guide.md

Server vs Client Components

服务器组件 vs 客户端组件

Use Server Components by default. Add 'use client' only when you need:
  • Event handlers (onClick, onChange)
  • State (useState, useReducer)
  • Effects (useEffect)
  • Browser APIs
tsx
// 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>;
}
默认使用服务器组件。仅在需要以下功能时添加'use client':
  • 事件处理器(onClick、onChange)
  • 状态(useState、useReducer)
  • 副作用(useEffect)
  • 浏览器API
tsx
// 服务器组件(默认)- 无'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>;
}

Image Optimization

图片优化

tsx
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>
tsx
import Image from 'next/image';

// 首屏图片 - 立即加载
<Image
  src="/hero.jpg"
  alt="首屏图"
  width={1200}
  height={600}
  priority
/>

// 响应式填充图片
<div className="relative aspect-video">
  <Image
    src="/product.jpg"
    alt="产品图"
    fill
    sizes="(max-width: 768px) 100vw, 50vw"
    className="object-cover"
  />
</div>

Data Fetching Patterns

数据获取模式

tsx
// 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>
  );
}

tsx
// 并行获取数据
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>
  );
}

Accessibility and Testing

无障碍与测试

Reference:
references/frontend_best_practices.md
参考:
references/frontend_best_practices.md

Accessibility Checklist

无障碍检查清单

  1. Semantic HTML: Use proper elements (
    <button>
    ,
    <nav>
    ,
    <main>
    )
  2. Keyboard Navigation: All interactive elements focusable
  3. ARIA Labels: Provide labels for icons and complex widgets
  4. Color Contrast: Minimum 4.5:1 for normal text
  5. Focus Indicators: Visible focus states
tsx
// 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>
  1. 语义化HTML:使用合适的元素(
    <button>
    <nav>
    <main>
  2. 键盘导航:所有交互元素可聚焦
  3. ARIA标签:为图标和复杂组件提供标签
  4. 颜色对比度:普通文本最低4.5:1
  5. 焦点指示器:可见的焦点状态
tsx
// 无障碍按钮
<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>

Testing Strategy

测试策略

tsx
// 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');
});

tsx
// 使用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);
});

// 无障碍测试
test('对话框符合无障碍标准', async () => {
  render(<Dialog open={true} title="确认" />);

  expect(screen.getByRole('dialog')).toBeInTheDocument();
  expect(screen.getByRole('dialog')).toHaveAttribute('aria-labelledby');
});

Quick Reference

快速参考

Common Next.js Config

常见Next.js配置

js
// next.config.js
const nextConfig = {
  images: {
    remotePatterns: [{ hostname: 'cdn.example.com' }],
    formats: ['image/avif', 'image/webp'],
  },
  experimental: {
    optimizePackageImports: ['lucide-react', '@heroicons/react'],
  },
};
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 Utilities

Tailwind CSS工具类

tsx
// 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'
)} />
tsx
// 使用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 Patterns

TypeScript模式

tsx
// 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>;
}

tsx
// 包含子元素的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>;
}

Resources

资源

  • React Patterns:
    references/react_patterns.md
  • Next.js Optimization:
    references/nextjs_optimization_guide.md
  • Best Practices:
    references/frontend_best_practices.md
  • React模式:
    references/react_patterns.md
  • Next.js优化:
    references/nextjs_optimization_guide.md
  • 最佳实践:
    references/frontend_best_practices.md