Skill 总结

15 阅读13分钟

一、前端项目分析与技能生成

---
name: project-analysis-and-skill-generator
description: 深度分析当前项目代码结构、技术栈与开发规范,自动生成一系列符合项目特性的 Skill 文档,用于指导后续开发。
---

# 项目代码分析与技能生成器 (Project Analysis & Skill Generator)

作为一个资深的前端架构师智能体,你的任务是**深度分析当前项目的代码库**,理解其技术栈、架构模式、命名规范和最佳实践,并基于这些分析结果,在 `.trae/skills/` 目录下生成一系列**可执行的 Skill 文档**## 1. 核心任务目标
1.  **全面扫描**:扫描项目根目录及 `src` 目录,识别项目使用的核心技术(React/Vue/Angular, TypeScript, CSS预处理器, 构建工具等)。
2.  **规范提取**:从现有代码中提取命名规范(文件、变量、类、组件)、代码风格(ESLint/Prettier)、目录结构规范。
3.  **技能生成**:针对下述 16 个关键维度进行分析,如果项目中存在相关代码,则生成对应的 Skill Markdown 文件。
4.  **索引汇总**:生成一个汇总的 `SKILL.md`,作为所有生成的 Skill 的索引和使用指南。

## 2. 分析与生成维度 (Analysis Dimensions)

请针对以下每个维度进行代码分析。如果项目中包含相关实现,请生成独立的 Skill 文件(例如 `component-development.md`)。

**注意:** 如果项目中完全不存在某个维度的代码(例如没有使用 Vuex/Redux),则跳过该 Skill 的生成。

### 2.1 基础架构与规范
1.  **环境配置 (Environment Setup)**
    *   分析 `.env`, `vite.config.ts`, `webpack.config.js` 等。
    *   提取环境变量命名规范、代理配置、构建优化策略。
2.  **配置文件定义与使用 (Configuration Management)**
    *   分析项目自定义的配置文件或常量定义文件。
    *   提取配置项的读取方式和类型定义。
3.  **ESLint/Prettier 规范遵守 (Linting & Formatting)**
    *   分析 `.eslintrc`, `.prettierrc`    *   提取关键的 Lint 规则(如禁止 console, 强制单引号等)。
4.  **TypeScript 定义与使用 (TypeScript Usage)**
    *   分析 `tsconfig.json``src/**/*.d.ts`    *   提取类型定义习惯(Interface vs Type)、泛型使用、工具类型封装。
5.  **CSS/Less/SCSS 规范 (Styling Guidelines)**
    *   分析样式文件,确定预处理器(Less/Sass/Stylus/Tailwind)。
    *   提取 BEM 命名规范、CSS Modules 使用、全局变量定义。
6.  **代码优化规范 (Code Optimization)**
    *   分析代码中的性能优化模式(懒加载、Memoization、Virtual List)。
    *   提取代码分割(Code Splitting)策略。

### 2.2 核心功能开发
7.  **组件封装与使用 (Component Development)**
    *   分析 `src/components`    *   提取组件目录结构(扁平 vs 嵌套)、Props 定义、Slot 使用、事件发射规范。
8.  **指令封装与使用 (Directive Development)**
    *   (Vue/Angular) 分析自定义指令的实现和注册方式。
9.  **路由定义与文件命名 (Routing)**
    *   分析 `src/router``src/pages` (Next.js/Nuxt)。
    *   提取路由配置模式(动态路由、嵌套路由)、路由守卫(Guard)、路由懒加载写法。
10. **全局数据定义与使用 (State Management)**
    *   分析 `src/store` (Pinia/Vuex) 或 Redux/MobX/Zustand。
    *   提取 Store 的模块化结构、Action/Mutation/Reducer 的命名和调用规范。

### 2.3 业务逻辑与交互
11. **表单生成与校验 (Forms & Validation)**
    *   分析表单组件的使用。
    *   **关键点**:提取防重复提交策略(Loading 锁)、校验规则定义(Async Validator/Zod/Yup)。
12. **列表的增删改查 (CRUD Operations)**
    *   分析列表页面。
    *   **关键点**:提取搜索栏封装、分页处理、操作按钮防抖(Debounce)/节流(Throttle)处理。
13. **接口联调 (API Integration)**
    *   分析 `src/api``src/services`    *   提取 Axios/Fetch 封装、请求拦截器(Token 注入)、响应拦截器(错误处理)、接口定义规范。
14. **权限控制 (Permission Control)**
    *   分析权限管理逻辑(指令、高阶组件、路由守卫)。
    *   提取按钮级权限和页面级权限的实现方式。
15. **文件上传 (File Upload)**
    *   分析文件上传组件或服务。
    *   提取上传流程(预签名、分片上传)、格式/大小校验逻辑。
16. **工具函数定义与使用 (Utils & Helpers)**
    *   分析 `src/utils``src/helpers`    *   提取常用工具函数(日期格式化、深拷贝、正则校验)的分类和命名。

### 2.4 动态发现与扩展 (Dynamic Discovery & Custom Logic)
除了上述标准维度外,智能体必须主动识别项目中特有的自定义逻辑和模块:

17. **自定义目录分析 (Custom Directory Analysis)**
    *   扫描 `src` 下所有未被上述维度覆盖的一级目录(例如 `src/hooks`, `src/constants`, `src/layouts`, `src/plugins`, `src/middleware`, `src/directives`, `src/filters` 等)。
    *   **生成规则**:对于每个包含重要逻辑(文件数量 > 3 或被频繁引用)的目录,生成独立的 Skill 文件,命名为 `[directory-name]-guide.md`(例如 `hooks-guide.md`)。
    *   **内容要求**:分析该目录的设计意图、文件组织方式、核心模式和使用场景。

18. **复杂/业务组件识别 (Complex Business Components)**
    *   深度扫描 `src/components``src/views` 下的子目录。
    *   如果发现具有高度复用性但包含特定业务逻辑的组件簇(不同于基础 UI 组件),生成 `business-components.md`    *   **关注点**:业务逻辑封装、数据获取方式、与 Store 的交互。

19. **特殊设计模式识别 (Special Design Patterns)**
    *   分析代码中是否存在特定的设计模式实现(如发布订阅 `EventBus`、依赖注入 `DI`、单例模式管理器、Web Worker 管理器、WebSocket 封装等)。
    *   如果存在,生成 `special-patterns.md` 或具体的 `[pattern-name].md`## 3. 生成的 Skill 文件规范 (Output Standard)

每个生成的 `.md` 文件(如 `component-development.md`)必须遵循以下结构:

```markdown
---
name: [技能名称,如 Component Development]
description: [简短描述,如 Vue3 组件开发规范与最佳实践]
---

# [技能名称] 开发指南

## 1. 核心规范 (Core Standards)
- **文件命名**: (例如 PascalCase)
- **目录结构**: (例如每个组件独立文件夹,包含 index.ts 和 style.scss)
- **技术选型**: (例如使用 setup script)

## 2. 代码模板 (Code Templates)
*(提供符合项目当前规范的代码片段,必须包含详细注释)*

```typescript
// 示例代码
```

## 3. 关键注意事项 (Critical Notes)
- (例如:必须定义 Props 类型)
- (例如:样式必须使用 scoped)

## 4. 执行步骤 (Step-by-Step Guide)
1. 创建文件...
2. 定义 Props...
```

## 4. 索引文件生成规范 (Index File Standard)

所有子 Skill 生成完毕后,必须在 `.trae/skills/` 下生成 `SKILL.md` 索引文件:

```markdown
# 项目开发技能索引 (Project Skills Index)

本文件汇总了当前项目的所有开发技能规范。请在开发过程中参考相应的 Skill 文档。

## 技能列表

### 基础架构
- [环境配置](./environment-setup.md): 环境变量与构建配置说明
- ...

### 核心开发
- [组件开发](./component-development.md): 组件封装规范
- [API 联调](./api-integration.md): 接口调用与拦截器规范
- ...

## 使用指南
在 Trae 的对话框中,你可以直接通过 Skill 名称调用这些能力,例如:
- "帮我创建一个新组件" -> 将触发 `component-development` skill
- "对这个列表页添加搜索功能" -> 将参考 `crud-operations` skill
```

## 5. 执行流程 (Execution Workflow)

作为智能体,请按以下步骤执行本 Skill:

1.  **初始化**:读取 `package.json`,确定主框架(React/Vue/Angular)和语言(TS/JS)。
2.  **遍历分析**:遍历上述 19 个维度(含动态发现),检查项目中是否存在相关代码。
3.  **生成子 Skill**:
    *   对于每个存在的维度,分析其实现模式。
    *   在 `.trae/skills/` 下生成对应的 `.md` 文件(如果目录不存在则创建)。
    *   对于**动态发现**的目录,确保命名具有描述性。
    *   **重要**:生成的代码模板必须直接取自或基于项目中的现有代码,确保高度一致性。
4.  **生成索引**:生成 `SKILL.md` 汇总所有已生成的 Skill。
5.  **完成**:输出生成报告,列出已生成的 Skill 文件列表。

---
**注意**:此 Skill 本身不修改项目业务代码,只生成文档。生成过程应确保不覆盖用户手动编写的且未在本次生成范围内的其他 Skill 文件(除非同名覆盖)。

二、Vue3 代码优化

---
name: Vue3 代码优化
description: 用于优化 Vue3 项目代码性能、提升渲染效率、减少内存占用、改善用户体验。当用户需要优化 Vue3 应用性能或重构低效代码时调用。
---

你是一个资深的前端架构师,请按照以下规范为用户提供 Vue3 代码优化指导。

## 1. 核心规范

### 1.1 技术栈
- **框架**: Vue 3.4+
- **语言**: TypeScript 5.0+
- **构建**: Vite 5.0+
- **状态管理**: Pinia
- **UI 库**: Element Plus / Ant Design Vue

### 1.2 优化目标
- **首屏加载**: 减少初始包体积,提升 FCP/LCP
- **运行时性能**: 减少不必要的渲染,优化响应式追踪
- **内存管理**: 避免内存泄漏,及时清理副作用
- **用户体验**: 流畅的交互,合理的加载策略

## 2. 代码优化技巧

### 2.1 组件优化

#### 使用 `shallowRef` 和 `shallowReactive`

```typescript
import { shallowRef, shallowReactive } from 'vue';

// ❌ 深度响应式 - 性能开销大
const largeList = ref([
  { id: 1, name: 'Item 1', data: { /* 嵌套数据 */ } },
  { id: 2, name: 'Item 2', data: { /* 嵌套数据 */ } },
]);

// ✅ 浅层响应式 - 仅顶层响应式
const largeList = shallowRef([
  { id: 1, name: 'Item 1', data: { /* 嵌套数据 */ } },
  { id: 2, name: 'Item 2', data: { /* 嵌套数据 */ } },
]);

// 更新整个对象时触发响应
largeList.value = newList;
```

#### 使用 `markRaw` 跳过响应式转换

```typescript
import { markRaw } from 'vue';
import * as echarts from 'echarts';

// ❌ 第三方库实例被转为响应式
const chartInstance = ref(echarts.init(dom));

// ✅ 标记为原始对象,跳过响应式转换
const chartInstance = ref(markRaw(echarts.init(dom)));
```

#### 使用 `computed` 缓存计算结果

```typescript
import { ref, computed } from 'vue';

const list = ref([1, 2, 3, 4, 5]);

// ❌ 每次渲染都重新计算
const evenList = () => list.value.filter(item => item % 2 === 0);

// ✅ 缓存计算结果,依赖不变不重新计算
const evenList = computed(() => list.value.filter(item => item % 2 === 0));
```

### 2.2 列表渲染优化

#### 使用 `v-memo` 缓存列表项

```vue
<template>
  <div class="list">
    <div
      v-for="item in list"
      :key="item.id"
      v-memo="[item.id, item.name]"
      class="list-item"
    >
      <h3>{{ item.name }}</h3>
      <p>{{ item.description }}</p>
    </div>
  </div>
</template>
```

#### 虚拟滚动处理大数据列表

```typescript
// composables/useVirtualList.ts
import { ref, computed, onMounted, onUnmounted } from 'vue';

/**
 * 虚拟滚动组合式函数
 * @param list 原始数据列表
 * @param itemHeight 每项高度
 * @param containerHeight 容器高度
 */
export function useVirtualList<T>(
  list: Ref<T[]>,
  itemHeight: number,
  containerHeight: number
) {
  const scrollTop = ref(0);
  
  // 可视区域起始索引
  const startIndex = computed(() => {
    return Math.floor(scrollTop.value / itemHeight);
  });
  
  // 可视区域结束索引
  const endIndex = computed(() => {
    return Math.min(
      startIndex.value + Math.ceil(containerHeight / itemHeight) + 1,
      list.value.length
    );
  });
  
  // 可视区域数据
  const visibleList = computed(() => {
    return list.value.slice(startIndex.value, endIndex.value);
  });
  
  // 偏移量
  const offsetStyle = computed(() => {
    return {
      paddingTop: `${startIndex.value * itemHeight}px`,
      paddingBottom: `${(list.value.length - endIndex.value) * itemHeight}px`,
    };
  });
  
  const handleScroll = (e: Event) => {
    scrollTop.value = (e.target as HTMLElement).scrollTop;
  };
  
  return {
    visibleList,
    offsetStyle,
    handleScroll,
    startIndex,
  };
}
```

### 2.3 异步组件与懒加载

#### 路由懒加载

```typescript
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router';

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      name: 'Home',
      component: () => import('@/views/Home.vue'),
    },
    {
      path: '/about',
      name: 'About',
      // 使用 webpackChunkName 指定打包后的文件名
      component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue'),
    },
    {
      path: '/heavy',
      name: 'Heavy',
      // 预加载 - 空闲时加载
      component: () => import(/* webpackPrefetch: true */ '@/views/Heavy.vue'),
    },
  ],
});
```

#### 组件异步加载

```vue
<template>
  <div>
    <HeavyChart v-if="showChart" />
    <button @click="showChart = true">加载图表</button>
  </div>
</template>

<script setup lang="ts">
import { defineAsyncComponent, ref } from 'vue';
import { ElLoading } from 'element-plus';

// 异步加载重型组件
const HeavyChart = defineAsyncComponent({
  loader: () => import('@/components/HeavyChart.vue'),
  loadingComponent: () => import('@/components/ChartSkeleton.vue'),
  errorComponent: () => import('@/components/ErrorFallback.vue'),
  delay: 200,
  timeout: 3000,
});

const showChart = ref(false);
</script>
```

### 2.4 事件处理优化

#### 使用 `v-once` 和 `v-pre`

```vue
<template>
  <div>
    <!-- v-once: 只渲染一次,后续更新跳过 -->
    <h1 v-once>{{ staticTitle }}</h1>
    
    <!-- v-pre: 跳过编译,显示原始 Mustache 标签 -->
    <code v-pre>{{ 这里的内容不会被编译 }}</code>
  </div>
</template>
```

#### 防抖和节流

```typescript
// composables/useDebounce.ts
import { ref, watch } from 'vue';

/**
 * 防抖函数
 * @param value 响应式值
 * @param delay 延迟时间
 */
export function useDebounce<T>(value: Ref<T>, delay: number = 300) {
  const debouncedValue = ref(value.value);
  let timeoutId: ReturnType<typeof setTimeout>;
  
  watch(value, (newValue) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      debouncedValue.value = newValue;
    }, delay);
  });
  
  return debouncedValue;
}

// 使用示例
const searchText = ref('');
const debouncedSearchText = useDebounce(searchText, 500);

// 监听防抖后的值触发搜索
watch(debouncedSearchText, (val) => {
  performSearch(val);
});
```

```typescript
// composables/useThrottle.ts
import { ref } from 'vue';

/**
 * 节流函数
 * @param fn 要节流的函数
 * @param limit 时间限制
 */
export function useThrottle<T extends (...args: any[]) => any>(
  fn: T,
  limit: number = 100
) {
  let inThrottle = false;
  
  return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => {
        inThrottle = false;
      }, limit);
    }
  };
}

// 使用示例
const handleScroll = useThrottle((e: Event) => {
  console.log('滚动位置:', (e.target as HTMLElement).scrollTop);
}, 100);
```

### 2.5 内存管理优化

#### 及时清理副作用

```typescript
import { onMounted, onUnmounted } from 'vue';

// composables/useEventListener.ts
export function useEventListener(
  target: EventTarget,
  event: string,
  callback: EventListener
) {
  onMounted(() => {
    target.addEventListener(event, callback);
  });
  
  onUnmounted(() => {
    target.removeEventListener(event, callback);
  });
}

// composables/useInterval.ts
export function useInterval(callback: () => void, delay: number) {
  let timer: ReturnType<typeof setInterval>;
  
  onMounted(() => {
    timer = setInterval(callback, delay);
  });
  
  onUnmounted(() => {
    clearInterval(timer);
  });
}
```

#### 清理第三方实例

```typescript
import { ref, onMounted, onUnmounted, markRaw } from 'vue';
import * as echarts from 'echarts';

export function useECharts() {
  const chartRef = ref<HTMLDivElement>();
  const chartInstance = ref<echarts.ECharts | null>(null);
  
  const initChart = (option: echarts.EChartsOption) => {
    if (chartRef.value) {
      // 使用 markRaw 避免响应式转换
      chartInstance.value = markRaw(echarts.init(chartRef.value));
      chartInstance.value.setOption(option);
    }
  };
  
  const updateChart = (option: echarts.EChartsOption) => {
    chartInstance.value?.setOption(option);
  };
  
  const resizeChart = () => {
    chartInstance.value?.resize();
  };
  
  onUnmounted(() => {
    // 销毁实例,释放内存
    chartInstance.value?.dispose();
    chartInstance.value = null;
  });
  
  return {
    chartRef,
    initChart,
    updateChart,
    resizeChart,
  };
}
```

### 2.6 状态管理优化

#### Pinia Store 优化

```typescript
// stores/user.ts
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';

export const useUserStore = defineStore('user', () => {
  // State
  const userInfo = ref<UserInfo | null>(null);
  const permissions = ref<string[]>([]);
  
  // Getters - 使用 computed 缓存
  const isLoggedIn = computed(() => !!userInfo.value);
  const hasPermission = computed(() => {
    return (permission: string) => permissions.value.includes(permission);
  });
  
  // Actions
  const setUserInfo = (info: UserInfo) => {
    userInfo.value = info;
  };
  
  const clearUserInfo = () => {
    userInfo.value = null;
    permissions.value = [];
  };
  
  return {
    userInfo,
    permissions,
    isLoggedIn,
    hasPermission,
    setUserInfo,
    clearUserInfo,
  };
});
```

#### 选择性订阅 State

```typescript
import { storeToRefs } from 'pinia';
import { useUserStore } from '@/stores/user';

// ❌ 直接解构会失去响应性,且订阅整个 store
const { userInfo, permissions } = useUserStore();

// ✅ 使用 storeToRefs 保持响应性,只订阅需要的 state
const userStore = useUserStore();
const { userInfo, permissions } = storeToRefs(userStore);

// 方法可以直接解构
const { setUserInfo } = userStore;
```

## 3. 注意事项

### 3.1 避免的性能陷阱

1. **避免在 `v-for` 中使用 `v-if`**
   ```vue
   <!-- ❌ 错误:每次渲染都遍历整个列表 -->
   <div v-for="item in list" :key="item.id">
     <span v-if="item.active">{{ item.name }}</span>
   </div>
   
   <!-- ✅ 正确:先过滤再渲染 -->
   <div v-for="item in activeList" :key="item.id">
     <span>{{ item.name }}</span>
   </div>
   ```

2. **避免在模板中执行复杂计算**
   ```vue
   <!-- ❌ 错误:每次渲染都执行复杂计算 -->
   <div>{{ complexCalculation(data) }}</div>
   
   <!-- ✅ 正确:使用 computed 缓存结果 -->
   <div>{{ computedResult }}</div>
   ```

3. **避免不必要的响应式转换**
   ```typescript
   // ❌ 错误:大量静态数据被转为响应式
   const staticData = ref(largeStaticData);
   
   // ✅ 正确:使用 shallowRef 或 markRaw
   const staticData = shallowRef(largeStaticData);
   ```

### 3.2 最佳实践

1. **合理使用 `key` 属性**
   - 列表渲染必须提供唯一的 `key`
   - 避免使用数组索引作为 `key`(除非列表不会变化)

2. **组件拆分**
   - 将大型组件拆分为小型、专注的组件
   - 减少不必要的渲染范围

3. **Props 稳定性**
   - 保持 Props 引用稳定,避免不必要的子组件更新
   - 使用 `toRefs` 解构 Props 保持响应性

4. **异步数据加载**
   - 使用 Suspense 处理异步组件
   - 提供加载状态和错误边界

## 4. 执行步骤

### 4.1 性能分析

1. **使用 Vue DevTools**
   - 打开 Performance 面板
   - 记录组件渲染时间
   - 识别渲染瓶颈

2. **使用 Chrome DevTools**
   - Performance 面板分析运行时性能
   - Memory 面板检测内存泄漏
   - Lighthouse 生成性能报告

### 4.2 优化流程

1. **识别问题**
   - 首屏加载慢 → 代码分割、懒加载、资源优化
   - 交互卡顿 → 防抖节流、虚拟滚动、减少重渲染
   - 内存泄漏 → 清理副作用、销毁实例、解除引用

2. **实施优化**
   - 按照优化技巧逐步实施
   - 每次优化后验证效果

3. **验证结果**
   - 对比优化前后的性能指标
   - 确保功能正常,无回归问题

### 4.3 性能指标监控

```typescript
// 监控核心 Web 指标
import { onMounted } from 'vue';

export function usePerformanceMonitor() {
  onMounted(() => {
    // LCP (Largest Contentful Paint)
    new PerformanceObserver((list) => {
      const entries = list.getEntries();
      const lastEntry = entries[entries.length - 1];
      console.log('LCP:', lastEntry.startTime);
    }).observe({ entryTypes: ['largest-contentful-paint'] });
    
    // FID (First Input Delay)
    new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        const delay = entry.processingStart - entry.startTime;
        console.log('FID:', delay);
      }
    }).observe({ entryTypes: ['first-input'] });
    
    // CLS (Cumulative Layout Shift)
    let clsValue = 0;
    new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        if (!entry.hadRecentInput) {
          clsValue += entry.value;
        }
      }
      console.log('CLS:', clsValue);
    }).observe({ entryTypes: ['layout-shift'] });
  });
}
```

## 5. 工具推荐

| 工具 | 用途 |
|------|------|
| Vue DevTools | 组件调试、性能分析 |
| Chrome DevTools | 性能剖析、内存分析 |
| Lighthouse | 性能评分、优化建议 |
| vite-bundle-visualizer | 包体积分析 |
| rollup-plugin-visualizer | 打包结果可视化 |

## 6. 总结

Vue3 性能优化是一个系统工程,需要从多个维度考虑:

1. **代码层面**: 合理使用响应式 API,避免不必要的计算和渲染
2. **架构层面**: 组件拆分、懒加载、代码分割
3. **资源层面**: 图片优化、CDN、缓存策略
4. **监控层面**: 建立性能指标监控体系

通过持续的性能优化和监控,可以确保 Vue3 应用保持良好的用户体验。