home / skills / aaaaqwq / agi-super-skills / frontend-development

frontend-development skill

/skills/frontend/frontend-development

This skill helps you build scalable frontend web apps, create reusable UI components, and optimize performance across React, Vue, and Angular workflows.

npx playbooks add skill aaaaqwq/agi-super-skills --skill frontend-development

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
14.0 KB
---
name: frontend-development
description: 前端页面开发。当用户需要开发 Web 应用、创建 UI 组件、实现交互功能或优化前端性能时使用此技能。
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
---

# 前端页面开发

## 功能说明
此技能专门用于前端 Web 开发,包括:
- 现代前端框架开发(React、Vue、Angular)
- 响应式页面布局
- 交互功能实现
- 状态管理
- 性能优化
- 前端工程化

## 使用场景
- "创建一个 React 登录页面"
- "实现一个响应式导航栏"
- "优化页面加载性能"
- "集成第三方 API"
- "实现深色模式切换"
- "创建可复用的 UI 组件库"

## 技术栈

### 核心框架
- **React**:组件化、Hooks、Context
- **Vue**:响应式、组合式 API、Pinia
- **Angular**:TypeScript、依赖注入、RxJS
- **Next.js**:SSR、SSG、API Routes
- **Nuxt.js**:Vue SSR 框架

### UI 框架
- **Tailwind CSS**:实用优先的 CSS 框架
- **Material-UI**:React Material Design
- **Ant Design**:企业级 UI 组件库
- **Element Plus**:Vue 3 组件库
- **Chakra UI**:可访问的组件系统

### 状态管理
- **Redux**:可预测的状态容器
- **Zustand**:轻量级状态管理
- **Pinia**:Vue 状态管理
- **MobX**:响应式状态管理
- **Jotai**:原子化状态管理

### 构建工具
- **Vite**:下一代前端构建工具
- **Webpack**:模块打包器
- **Turbopack**:Rust 驱动的打包器
- **esbuild**:极速 JavaScript 打包器

## 开发工作流程

### 项目初始化
1. **创建项目**:使用脚手架工具
2. **配置环境**:ESLint、Prettier、TypeScript
3. **目录结构**:组织代码文件
4. **依赖安装**:安装必要的包
5. **Git 初始化**:版本控制设置

### 开发流程
1. **需求分析**:理解功能需求
2. **组件设计**:拆分组件结构
3. **样式开发**:实现 UI 设计
4. **功能实现**:编写业务逻辑
5. **测试验证**:单元测试和集成测试
6. **代码审查**:团队 Code Review
7. **部署上线**:构建和发布

## 最佳实践

### 代码组织
```
src/
├── components/       # 可复用组件
│   ├── Button/
│   ├── Input/
│   └── Modal/
├── pages/           # 页面组件
│   ├── Home/
│   ├── Login/
│   └── Dashboard/
├── hooks/           # 自定义 Hooks
├── utils/           # 工具函数
├── services/        # API 服务
├── store/           # 状态管理
├── styles/          # 全局样式
├── types/           # TypeScript 类型
└── constants/       # 常量定义
```

### 组件设计原则
- **单一职责**:一个组件只做一件事
- **可复用性**:设计通用的组件
- **可组合性**:小组件组合成大组件
- **Props 验证**:使用 TypeScript 或 PropTypes
- **默认值**:提供合理的默认属性

### 性能优化
- **代码分割**:动态导入和懒加载
- **虚拟滚动**:处理大列表
- **防抖节流**:优化事件处理
- **Memo 化**:避免不必要的重渲染
- **图片优化**:懒加载、WebP 格式
- **缓存策略**:合理使用缓存

### 可访问性
- **语义化 HTML**:使用正确的标签
- **键盘导航**:支持键盘操作
- **ARIA 属性**:辅助技术支持
- **对比度**:确保文字可读性
- **焦点管理**:清晰的焦点指示

## 代码示例

### React 组件示例
```tsx
import React, { useState } from 'react';
import styled from 'styled-components';

interface ButtonProps {
  variant?: 'primary' | 'secondary';
  size?: 'small' | 'medium' | 'large';
  disabled?: boolean;
  onClick?: () => void;
  children: React.ReactNode;
}

const StyledButton = styled.button<ButtonProps>`
  padding: ${props => {
    switch (props.size) {
      case 'small': return '8px 16px';
      case 'large': return '16px 32px';
      default: return '12px 24px';
    }
  }};
  background: ${props =>
    props.variant === 'primary' ? '#2196F3' : '#757575'
  };
  color: white;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.2s;

  &:hover:not(:disabled) {
    opacity: 0.9;
    transform: translateY(-2px);
  }

  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
`;

export const Button: React.FC<ButtonProps> = ({
  variant = 'primary',
  size = 'medium',
  disabled = false,
  onClick,
  children
}) => {
  return (
    <StyledButton
      variant={variant}
      size={size}
      disabled={disabled}
      onClick={onClick}
    >
      {children}
    </StyledButton>
  );
};
```

### Vue 组件示例
```vue
<template>
  <button
    :class="buttonClasses"
    :disabled="disabled"
    @click="handleClick"
  >
    <slot />
  </button>
</template>

<script setup lang="ts">
import { computed } from 'vue';

interface Props {
  variant?: 'primary' | 'secondary';
  size?: 'small' | 'medium' | 'large';
  disabled?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  variant: 'primary',
  size: 'medium',
  disabled: false
});

const emit = defineEmits<{
  click: [];
}>();

const buttonClasses = computed(() => [
  'btn',
  `btn-${props.variant}`,
  `btn-${props.size}`,
  { 'btn-disabled': props.disabled }
]);

const handleClick = () => {
  if (!props.disabled) {
    emit('click');
  }
};
</script>

<style scoped>
.btn {
  padding: 12px 24px;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.2s;
}

.btn-primary {
  background: #2196F3;
  color: white;
}

.btn-secondary {
  background: #757575;
  color: white;
}

.btn-small {
  padding: 8px 16px;
  font-size: 14px;
}

.btn-large {
  padding: 16px 32px;
  font-size: 18px;
}

.btn:hover:not(.btn-disabled) {
  opacity: 0.9;
  transform: translateY(-2px);
}

.btn-disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
</style>
```

### 自定义 Hook 示例
```typescript
import { useState, useEffect } from 'react';

interface FetchState<T> {
  data: T | null;
  loading: boolean;
  error: Error | null;
}

export function useFetch<T>(url: string): FetchState<T> {
  const [state, setState] = useState<FetchState<T>>({
    data: null,
    loading: true,
    error: null
  });

  useEffect(() => {
    let cancelled = false;

    const fetchData = async () => {
      try {
        setState(prev => ({ ...prev, loading: true }));
        const response = await fetch(url);

        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }

        const data = await response.json();

        if (!cancelled) {
          setState({ data, loading: false, error: null });
        }
      } catch (error) {
        if (!cancelled) {
          setState({
            data: null,
            loading: false,
            error: error as Error
          });
        }
      }
    };

    fetchData();

    return () => {
      cancelled = true;
    };
  }, [url]);

  return state;
}
```

### 状态管理示例(Zustand)
```typescript
import create from 'zustand';
import { persist } from 'zustand/middleware';

interface User {
  id: string;
  name: string;
  email: string;
}

interface AuthState {
  user: User | null;
  token: string | null;
  isAuthenticated: boolean;
  login: (user: User, token: string) => void;
  logout: () => void;
}

export const useAuthStore = create<AuthState>()(
  persist(
    (set) => ({
      user: null,
      token: null,
      isAuthenticated: false,
      login: (user, token) =>
        set({ user, token, isAuthenticated: true }),
      logout: () =>
        set({ user: null, token: null, isAuthenticated: false })
    }),
    {
      name: 'auth-storage'
    }
  )
);
```

## 响应式设计

### 断点系统
```css
/* Mobile First */
/* Mobile: 默认样式 */
.container {
  padding: 16px;
}

/* Tablet: >= 768px */
@media (min-width: 768px) {
  .container {
    padding: 24px;
  }
}

/* Desktop: >= 1024px */
@media (min-width: 1024px) {
  .container {
    padding: 32px;
    max-width: 1200px;
    margin: 0 auto;
  }
}

/* Large Desktop: >= 1440px */
@media (min-width: 1440px) {
  .container {
    max-width: 1400px;
  }
}
```

### Flexbox 布局
```css
.flex-container {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

@media (max-width: 768px) {
  .flex-container {
    flex-direction: column;
  }
}
```

### Grid 布局
```css
.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 24px;
  padding: 24px;
}
```

## 测试策略

### 单元测试(Jest + React Testing Library)
```typescript
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';

describe('Button', () => {
  it('renders correctly', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByText('Click me')).toBeInTheDocument();
  });

  it('calls onClick when clicked', () => {
    const handleClick = jest.fn();
    render(<Button onClick={handleClick}>Click me</Button>);

    fireEvent.click(screen.getByText('Click me'));
    expect(handleClick).toHaveBeenCalledTimes(1);
  });

  it('is disabled when disabled prop is true', () => {
    render(<Button disabled>Click me</Button>);
    expect(screen.getByText('Click me')).toBeDisabled();
  });
});
```

### E2E 测试(Playwright)
```typescript
import { test, expect } from '@playwright/test';

test('user can login', async ({ page }) => {
  await page.goto('http://localhost:3000/login');

  await page.fill('input[name="email"]', '[email protected]');
  await page.fill('input[name="password"]', 'password123');
  await page.click('button[type="submit"]');

  await expect(page).toHaveURL('http://localhost:3000/dashboard');
  await expect(page.locator('h1')).toContainText('Dashboard');
});
```

## 部署和优化

### 构建优化
```javascript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          ui: ['@mui/material']
        }
      }
    },
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true
      }
    }
  }
});
```

### 环境变量
```env
# .env.production
VITE_API_URL=https://api.production.com
VITE_APP_NAME=My App
```



### Windows下Vite进程管理(重要!)

**问题**:Windows环境下Vite开发服务器退出时,chokidar文件监听器可能不会正确清理,导致僵尸进程占用端口。

**解决方案**:

1. **优化vite.config.js配置**
```javascript
export default defineConfig({
  server: {
    host: '0.0.0.0',
    port: 5173,
    strictPort: false,
    watch: { usePolling: false, interval: 1000 }
  },
  optimizeDeps: { exclude: ['@vueup/vue-quill'] }
})
```

2. **创建清理脚本 stop-dev.bat**
```batch
@echo off
echo Killing Vite processes...
for /f "tokens=5" %%a in ('netstat -ano ^| findstr :5173 2^>nul ^| findstr LISTENING') do (
  taskkill /F /PID %%a 2>nul
)
echo Done!
```

3. **创建智能启动脚本 dev.bat**
```batch
@echo off
echo Starting Vite dev server...
cmd /c npm run dev
for /f "tokens=5" %%a in ('netstat -ano ^| findstr :5173 2^>nul ^| findstr LISTENING') do (
  taskkill /F /PID %%a 2>nul
)
echo Vite stopped
```

**使用方法**:使用`dev.bat`启动,`stop-dev.bat`清理,避免后台运行。

## 注意事项
- 遵循团队代码规范
- 编写清晰的注释和文档
- 考虑浏览器兼容性
- 注意安全问题(XSS、CSRF)
- 优化首屏加载时间
- 实现错误边界和降级方案
- 使用 TypeScript 提高代码质量

---

## ⚠️ 文档同步规范(非常重要!)

前端开发完成后,**必须同步更新相关文档**,保持代码与文档一致!

### 必须维护的文档

#### 1. 进度文档 (`docs/frontend/progress.md`)
记录开发进度、已完成功能、待办事项。

**更新时机**:
- 完成新页面/组件时
- 修改技术栈时
- 完成里程碑时

**文档格式参考**:
```markdown
# 前端开发进度

> 最后更新:YYYY-MM-DD
> 状态:开发中 (X%完成)

## 已完成功能
### 核心架构
| 模块 | 状态 | 说明 |
|------|------|------|
| 项目初始化 | ✅ | Vite + Vue3 + Pinia |

## 待完成功能
### 优先级 P1
- [ ] 深色模式

## 代码统计
| 类型 | 数量 |
|------|------|
| 页面组件 | 8 |
```

#### 2. API对接文档 (`docs/frontend/api-reference.md`)
记录后端API接口、请求格式、响应格式。

**更新时机**:
- 后端新增/修改API时
- 前端调用新API时
- API字段变化时

**必须包含**:
- 服务地址配置
- 通用响应格式
- 每个API的详细说明(方法、路径、参数、响应示例)
- 前端调用示例代码

#### 3. README.md (`frontend/README.md`)
项目入口文档,快速上手指南。

**必须包含**:
- 项目简介
- 技术栈版本
- 快速启动命令
- 目录结构
- 开发注意事项
- 与后端的对接说明

### 文档同步检查清单

前端开发完成后,问自己:

- [ ] 我更新了 `docs/frontend/progress.md` 吗?
- [ ] 新API调用记录在 `docs/frontend/api-reference.md` 了吗?
- [ ] README.md 里的技术栈版本是最新的吗?
- [ ] 如果有环境变量变化,更新文档了吗?
- [ ] 代码结构变化后,更新目录结构了吗?

### 文档与代码同步原则

1. **先更新文档再提交代码** - 确保文档反映最新状态
2. **API变化立即同步** - 后端API变了,前端文档也要更新
3. **配置变化记录在案** - 环境变量、端口等配置变化要写进文档
4. **定期Review文档** - 每周检查一次文档是否过时
5. **删除死链接** - 不存在的功能从文档中移除

### 文档命名规范

| 文档类型 | 路径 | 命名格式 |
|----------|------|----------|
| 前端进度 | `docs/frontend/progress.md` | 固定文件名 |
| API参考 | `docs/frontend/api-reference.md` | 固定文件名 |
| 后端进度 | `docs/backend/progress.md` | 固定文件名 |
| 后端API参考 | `docs/backend/api-reference.md` | 固定文件名 |
| 技术设计 | `docs/plans/YYYY-MM-DD-*.md` | 按日期命名 |

---

Overview

This skill provides practical front-end development capabilities for building modern web applications, UI components, responsive layouts, and interactive features. It covers popular frameworks, state management, build tooling, performance optimization, testing strategies, and deployment tips. Use it to accelerate component design, implement accessibility, and standardize engineering workflows.

How this skill works

The skill inspects project requirements and suggests concrete implementation patterns: framework choice (React, Vue, Angular, Next.js/Nuxt), component structure, styling approach (Tailwind, CSS-in-JS), and state solution (Redux, Zustand, Pinia). It outputs code snippets, directory layouts, build and config examples, troubleshooting steps (including platform-specific process handling), and documentation checklists to keep code and docs synchronized.

When to use it

  • Starting a new front-end project or scaffold (Vite, Next, Nuxt)
  • Designing reusable UI components or a component library
  • Implementing responsive layouts and accessibility best practices
  • Optimizing performance: code-splitting, lazy loading, image strategies
  • Integrating third-party APIs and defining front-end API contracts
  • Setting up testing (unit/E2E) and CI/CD pipelines

Best practices

  • Organize code by components, pages, hooks, services, store, and types
  • Prefer single-responsibility components and design for composability and reuse
  • Enforce linting and formatting (ESLint, Prettier) and use TypeScript for prop/type safety
  • Optimize bundle with manualChunks, dynamic imports, and avoid heavy runtime libs
  • Prioritize accessibility: semantic HTML, ARIA, keyboard navigation, and focus management
  • Keep documentation updated: progress, API reference, and project README before merging

Example use cases

  • Create a React login page with form validation, accessibility, and tests
  • Implement a responsive navigation bar that collapses on mobile and supports keyboard navigation
  • Build a reusable Button component with variants, sizes, and disabled states (React/Vue examples provided)
  • Optimize initial load: split vendor chunks, lazy-load images, and configure Vite build terser options
  • Set up a persisted auth store with Zustand and demonstrate login/logout flows

FAQ

Which framework should I choose for a new project?

Choose based on team skill and requirements: React/Next for component flexibility and ecosystem, Vue/Nuxt for simplicity and convention, Angular for large typed apps with DI. Use SSR (Next/Nuxt) if SEO and fast first paint matter.

How do I avoid stuck Vite processes on Windows?

Use a small script to kill processes on the dev port or adjust vite.config server watch settings. Provide dev/stop batch scripts to start and clean up the Vite server reliably.