以项目中前端编码规范(vue-code-convention skill)为例,系统拆解如何将散落在代码、文档与团队经验中的前端项目规范,沉淀为可触发、可裁决、可执行、可验证、可持续迭代的 AI 开发 Skill。
当 AI 开始真正参与项目开发后,我们很快会遇到一个问题:它会写 Vue,也知道 TypeScript、Pinia 和 Vue Router,却不一定知道这个项目应该怎样写。
它可能把新页面放进技术上合理、但项目从未使用过的目录;可能在一个习惯使用 hooks/ 编排业务流程的仓库里新建 composables/;也可能为了追求“最佳实践”,顺手重构掉团队已经稳定运行多年的代码组织方式。
这并不代表 AI 不够聪明。恰恰相反,问题在于通用知识给了它太多合理答案,而项目开发需要的是一组经过团队选择的答案。
项目开发 Skill 的作用,就是把这些选择沉淀成 AI 可以理解和执行的项目上下文。它不是再写一份给人阅读的编码规范,也不是把 ESLint 文档复制进 Markdown,而是为 AI 建立一套决策系统:什么任务需要读取它、遇到冲突听谁的、哪些规则不能改变、哪些细节允许结合上下文判断,以及完成后怎样证明结果符合项目要求。
本文以我编写的 vue-code-convention 为例,讨论如何为自己的前端项目设计这样一套 Skill。
一、先分清:编码规范、提示词和 Skill 不是一回事
三者看起来都在“告诉 AI 怎么做”,但承担的职责不同。
| 载体 | 主要解决的问题 | 典型内容 |
|---|---|---|
| 编码规范 | 团队长期遵守什么 | 命名、目录、注释、请求与组件规范 |
| 提示词 | 这一次任务要做什么 | 目标、范围、验收标准、限制条件 |
| Skill | AI 在一类任务中如何持续做出符合项目的决策 | 触发条件、规则优先级、工作流、项目特有知识、验证方式 |
普通规范往往只描述结果,例如“组件文件使用 PascalCase”。一个有效的 Skill 还要补充它的适用范围、例外和冲突处理:页面模块目录使用 kebab-case,组件文件使用 PascalCase,路由入口必须是 index.vue。否则 AI 可能正确执行了某一句话,却破坏了整体结构。
提示词则不适合长期承载这些内容。每次都重复“API 方法必须以 Api 结尾、不要用 any、新业务模块放在哪里”,不仅低效,而且非常容易漏掉。
所以,可以把三者的关系概括为:
提示词描述本次任务,Skill 提供长期决策环境,代码与工具负责最终约束。
二、一个好 Skill 的原料,不是你记得的规范,而是仓库事实
很多人写项目 Skill 时,会先打开一个空白文档,凭记忆罗列“最佳实践”。这很容易写成一篇通用教程,而不是项目 Skill。
更可靠的方法是先做一次项目考古,从真实仓库中收集证据:
- 阅读
AGENTS.md (CLAUDE.md、copilot-instructions.md等)、README、架构文档和历史规范。 - 找出两到三个维护质量较高的代表模块。
- 对比新模块与遗留模块,区分“当前标准”和“历史包袱”。
- 查看
package.json、TypeScript、ESLint、Vite、测试和构建配置。 - 回顾 AI 或新成员最容易犯错的真实案例。
- 找出无法由静态工具检查、但会影响长期维护的项目决策。
vue-code-convention 中最有项目价值的部分,并不是“使用 const 而不是 var”这类通用知识,而是下面这类只看框架文档无法知道的信息:
src/views/<feature-module>/
├── index.vue
├── api/
├── components/
├── composables/
├── functional/
├── hooks/
├── config/
├── modules/
├── styles/
├── types/
├── utils/
└── locales/这个结构回答了大量实际问题:一个可路由的大型业务功能放在哪里,业务组件与低耦合复用单元如何区分,副作用和流程编排应该进入 hooks/ 还是 utils/,类型什么时候需要独立目录,哪些目录只能按需创建。
尤其重要的是,Skill 还明确说明:完整目录只是“目录词汇表”,不是每次创建模块时都要复制的脚手架。index.vue 必需,其余目录只有承担真实职责时才创建。这一句约束可以直接阻止 AI 生成一批空目录。
这就是项目 Skill 应该优先收录的内容:如果不告诉 AI,它仅凭通用能力很难从当前任务推断出来,并且猜错后会让项目逐渐失去一致性的知识。
三、先写使用场景,再写规则
开始写 Skill 之前,先列出它要处理的真实任务。比如 Vue 项目开发 Skill 至少要覆盖:
- 新建一个可由菜单独立承载的业务模块;
- 在现有模块中增加组件、接口或业务 Hook;
- 拆分一个体积过大的 Vue 页面;
- 重构数据请求、响应式状态或监听逻辑;
- 判断一段代码应该留在模块内部还是提升到共享目录;
- 修改已有功能,并按项目方式完成验证。
场景的价值在于暴露决策点。以“新增用户管理页”为例,AI 需要连续做出这些判断:
任务是否属于大型业务模块?
↓
应该放入哪个目录?
↓
需要创建哪些子目录?
↓
请求、状态、类型和组件分别放在哪里?
↓
应该沿用哪个现有模块?
↓
完成后执行哪些检查?如果 Skill 只能回答" Vue 代码用 <script setup> ",却无法回答这条决策链,它仍然只是一份代码风格清单。
建议为每个场景继续追问四个问题:
- AI 最容易在哪一步猜错?
- 仓库中哪个文件或模块代表正确做法?
- 这条规则是强制约束,还是可以因任务变化?
- 如何验证 AI 确实做对了?
最终写入 Skill 的不应是所有知识,而应是这些问题的高价值答案。
四、description 不是简介,而是 Skill 的触发器
Skill 的正文只有在触发后才会被读取。因此,frontmatter 中的 description 决定了 Skill 能否在正确的时机出现。
一个过于宽泛的描述可能是:
description: Vue 3 项目编码规范。它说明了主题,却没有说明何时使用。AI 面对“拆分用户管理页面”时,未必能判断这个 Skill 与目录重构有关。
vue-code-convention 的处理方式更接近一个触发条件:
---
name: vue-code-convention
description: Authoritative Vue 3 + TypeScript development conventions. MUST be loaded for new Vue feature development, feature refactoring, components, composables, hooks, API modules, directory structure decisions, async requests, reactive state, comments, and performance work.
---这里同时写明了三件事:
- 它是什么:Vue 3 + TypeScript 项目开发规范;
- 什么时候使用:新功能、功能重构、组件、Hook、API、目录、请求和性能工作;
- 它的地位是什么:在相关项目决策中属于权威来源。
编写自己的 description 时,可以使用下面这个公式:
能力范围 + 具体触发任务 + 关键项目对象 + 必要的权威说明不要把“什么时候使用”只写在正文的“适用场景”章节中,因为 AI 在决定是否加载 Skill 时还看不到正文。
五、真正决定执行质量的,是规则优先级
一个前端任务可能同时触发多个 Skill:Vue 规范、UI 设计、无障碍、性能、Pinia、Router、测试等。它们各自都可能合理,却不一定与当前项目的目录结构和历史选择一致。
因此,项目 Skill 必须声明冲突如何解决。vue-code-convention 给出的优先级是:
1. 用户的明确要求
2. 仓库中的 AGENTS.md (CLAUDE.md、copilot-instructions.md等)
3. vue-code-convention
4. 其他 Vue 与前端 Skill同时,它进一步限定:其他 Skill 可以优化类型、组件设计、测试、可访问性和性能,但不能替换项目规定的功能目录结构。
这段内容的价值,远高于再增加十条代码风格。因为它划出了“允许优化”和“禁止改写”的边界:
- 项目 Skill 负责定义本仓库的稳定骨架;
- 专项 Skill 负责提高局部实现质量;
- 用户仍然可以明确要求一次例外;
- AI 不需要在多个看似同级的建议之间自行猜测。
如果项目中同时存在仓库规则和个人 Skill,也必须避免重复维护同一条规范。比较合适的职责划分是:
AGENTS.md (CLAUDE.md、copilot-instructions.md等)放置仓库级协作规则、Skill 选择规则和最高层约束;- 项目 Skill 放置某类开发任务的完整决策知识;
- ESLint、TypeScript 和测试固化机器可检查的规则;
- 任务提示词只描述本次变更的目标和验收条件。
六、给规则分级:不是所有要求都应该写成 MUST
Skill 写得过松,AI 会自由发挥;写得过死,则会在不适用的场景机械执行。关键不是使用更多“必须”,而是为不同决策设置合适的自由度。
可以把前端项目规则分为四类:
| 类型 | 建议措辞 | 示例 |
|---|---|---|
| 不变量 | MUST / NEVER | 禁止 any;列表 key 不使用索引 |
| 项目默认值 | Prefer / 默认 | 大对象优先考虑 shallowRef |
| 条件规则 | When / Unless | 高频切换使用 v-show,低频重型节点使用 v-if |
| 判断型原则 | Decide based on | 是否增加单元测试取决于复用范围和回归风险 |
判断一条规则是否应该设为强制,可以问:
- 违反它是否一定造成错误或项目结构分裂?
- 是否存在合法而常见的反例?
- 工具能否自动校验?
- 项目当前代码是否已经稳定遵守?
例如,“独立请求全部放进 try...catch...finally”非常清晰,但 finally 只有在需要收尾逻辑时才产生实际价值;如果没有 loading、锁或临时状态需要恢复,强制空 finally 反而会制造噪声。更稳健的写法可以是:请求必须明确错误边界;存在必须执行的清理逻辑时使用 finally;禁止无错误处理的裸请求。
再比如,“600 行必须拆分”适合作为项目护栏,却不应成为唯一依据。一个 450 行、混合了请求编排、表格配置和弹窗状态的组件,可能早已需要拆分;一个结构单纯的声明式配置文件,即使略长,也未必应该被切碎。Skill 最好同时写清数字阈值与背后的维护目标。
规则越刚性,越需要严格验证它没有反例。MUST 不是强调语气,而是一项维护承诺。
七、用“规则 + 原因 + 正反例 + 例外”表达关键决策
只写结论,AI 容易机械套用;只讲原理,AI 又可能得出与项目不同的答案。对于重要规则,最有效的表达结构通常是:
规则 → 为什么 → 正确示例 → 错误示例 → 何时例外vue-code-convention 对 defineModel 的描述就是一个直观例子:
// Vue 3.4+
const visible = defineModel<boolean>("visible");
const count = defineModel<number>("count", { default: 0 });规则不只是“使用新 API”,还标明了版本前提,并给出了命名模型的写法。AI 因而能判断:只有项目版本满足 Vue 3.4+ 时才执行,维护旧版本项目时仍需使用 props + emits。
目录规则也适合这种表达方式:
hooks/ 放业务状态、副作用和流程编排
utils/ 放无状态纯函数
components/ 放带有业务逻辑的组件
composables/ 放低耦合复用单元相比“合理拆分文件”,这种边界定义更可执行。为了减少歧义,还可以补充一对具体示例:useUserTable 包含请求、loading 和生命周期,进入 hooks/;formatUserName 只接受参数并返回字符串,进入 utils/。
不过,原因不需要写成长篇教程。Skill 使用上下文是有限资源,应该优先保留会改变决策的信息。像“var 存在变量提升”通常是模型已经知道的常识;而“为什么本项目将 hooks/ 和 composables/ 分开”则值得解释。
八、把目录结构写成决策模型,而不是静态树
前端项目 Skill 中,目录结构往往是影响最大的规则,因为一次错误放置会被后续功能不断模仿。
仅提供目录树还不够,至少还要回答四类问题。
1. 什么时候启用这套结构
vue-code-convention 明确说明,这套结构面向可以由菜单独立承载的大型业务功能,例如用户管理和角色管理;简单功能不建议套用完整结构。
这能避免 AI 把一个只有几十行的小页面“架构”成十几个文件。
2. 哪些目录必需,哪些按需创建
路由页面的 index.vue 必需,其余目录按实际职责创建,不生成空占位目录。
3. 相邻目录的边界是什么
hooks/ 与 utils/、components/ 与 composables/、modules/ 与普通组件之间都需要明确区分。目录名称本身不能替代职责说明。
4. 代码何时升级为共享能力
如果多个功能都在复用同一段代码,应提升到 src/components、src/api 或 src/utils 等共享目录,而不是继续复制在各自模块中。
所以,一段完整的目录 Skill 不是“把文件放进哪里”的地图,而是“代码在什么条件下移动”的模型:
一次使用 → 就近放置
模块内多处复用 → 模块级目录
多个业务模块复用 → 项目共享目录
独立子业务 → modules/这个模型比不断增加目录名称更能维持项目边界。
九、把版本、事实和偏好分开
项目 Skill 经常混合三类内容:
- 语言或框架事实,例如
watchEffect的依赖收集时机; - 版本相关能力,例如 Vue 3.4 的
defineModel、Vue 3.5 的数字deep; - 团队偏好,例如函数统一使用
const箭头函数。
这三类内容的维护方式不同。框架事实需要与官方文档和实际运行结果一致;版本能力需要标明最低版本;团队偏好只要与项目共识一致即可,但不要包装成语言层面的绝对真理。
这一步非常重要,因为 Skill 里的代码会被 AI 当作可信参考。一个不存在的运算符、一段已经废弃的 API、一个与项目 TypeScript 版本不兼容的示例,都可能被复制到多个功能里。
例如在维护“现代运算符”章节时,应该使用编译器确认示例是否真实可用。??、?.、??= 是 JavaScript/TypeScript 支持的语法;如果文档中出现 ?= 这样的写法,就必须先确认它是否来自某个特定提案、编译插件或库,而不能仅凭记忆把它列为标准运算符。
类似地,目录命名也要区分层级:功能模块目录可以是 kebab-case,Vue 组件文件可以是 PascalCase。这不是互相矛盾,而是两个不同对象的命名规则。Skill 应该把对象写完整,避免只写“文件名使用 PascalCase”这样的宽泛结论。
十、不要把能自动检查的事情全部交给文字
Skill 擅长提供判断,工具擅长保证确定性。两者应该协作,而不是互相替代。
| 约束 | 更合适的载体 |
|---|---|
禁止 any、未使用变量、格式化 | TypeScript、ESLint、Prettier |
| 组件和模块应该放在哪里 | Skill |
| 公共 API 是否发生破坏性变化 | 类型检查、测试、构建 |
| 什么情况下拆分组件 | Skill + 代码审查 |
| 固定生成一组样板文件 | Skill 中的脚本或模板 |
| 功能是否符合真实交互 | 自动化测试或人工验证 |
如果某个检查每次都需要 AI 重新写一段脚本,就应考虑把它放进 Skill 的 scripts/;如果项目有稳定的页面或模块模板,可以放入 assets/;如果 API 约定、组件库文档或业务字典很长,可以拆到 references/ 中按需读取。
一个可扩展的项目 Skill 可以采用下面的结构:
vue-project-development/
├── SKILL.md
├── references/
│ ├── feature-structure.md
│ ├── api-conventions.md
│ └── testing-policy.md
├── scripts/
│ └── validate-feature-structure.mjs
└── assets/
└── feature-template/SKILL.md 只保留触发后的核心工作流、规则优先级和资源导航。只有任务涉及 API 时才读取 api-conventions.md,只有创建大型功能模块时才读取 feature-structure.md。这就是渐进式披露:让 AI 在正确的时间获得足够的信息,而不是每次都加载全部项目知识。
十一、验证策略必须写进 Skill
没有验证闭环的开发 Skill,只能提高“看起来像项目代码”的概率,不能保证结果真的可以合并。
一个项目级 Skill 至少要告诉 AI:
- 先从
package.json或项目文档发现可用命令,不要臆造命令; - 优先运行与改动直接相关的检查;
- 再根据风险执行 lint、类型检查、测试和构建;
- 已有测试不能删除、跳过或为了通过而弱化断言;
- 无法执行的检查必须说明原因;
- 不得声称没有实际运行的检查已经通过。
vue-code-convention 中“普通业务功能默认不强制新增单元测试”的策略也很有代表性。它没有简单套用“所有代码都必须测试”,而是把测试投入与项目现实连接起来:普通业务改动以 lint、类型检查、构建和针对性人工验证为主;共享库、公共契约和高风险逻辑再根据复杂度与回归风险决定是否增加单元测试。
这种规则比口号更可执行,因为它回答了“什么时候值得测试”。当然,每个团队的答案可以不同,关键是让 Skill 反映真实工程策略,而不是一套无法兑现的理想流程。
验证还应覆盖 Skill 自身:YAML frontmatter 是否有效、引用文件是否存在、示例能否通过编译、命令是否与当前项目一致、规则之间是否互相冲突。项目升级 Vue、TypeScript 或构建工具时,也要同步审查相关章节。
十二、用失败案例驱动 Skill 迭代
Skill 很难一次写完。真正高价值的规则,往往来自一次次具体失败:
- AI 把业务副作用放进了
utils/; - 为简单页面创建了完整目录树;
- 路由懒加载外又包了一层
defineAsyncComponent; - 在列表中使用索引作为
key; - 为遵守“必须测试”生成了大量低价值断言;
- 读取另一个设计 Skill 后重组了整个功能目录。
每次失败后,不要立刻增加一句更强硬的“禁止”。先判断失败发生在哪一层:
- 没有触发:补全 description 中的任务关键词。
- 触发后没找到信息:调整正文结构或资源导航。
- 规则有歧义:增加适用条件、正反例或目录边界。
- 多个规则冲突:补充优先级和例外处理。
- 执行结果不稳定:用脚本、模板或工具替代纯文字。
- 规则本身不合理:降低强制级别或删除它。
可以建立一份简单的评估集,用固定任务反复测试 Skill:
任务 A:新增一个大型用户管理模块
观察:目录是否按需创建,API、Hook、类型是否放置正确
任务 B:为已有页面增加两个并行请求
观察:是否正确处理 loading、错误边界和并行失败策略
任务 C:拆分一个 700 行组件
观察:是否按职责拆分,而不是按代码行数平均切割
任务 D:修改一个小型展示组件
观察:是否避免套用大型业务模块结构和无关重构评估时只给 AI 正常任务和 Skill,不要提前告诉它“标准答案”或你怀疑的问题,否则测到的只是提示能力,不是 Skill 的泛化能力。
十三、从 vue-code-convention 中可以继续提炼什么
整体来看,vue-code-convention 已经具备一个项目开发 Skill 的关键骨架:覆盖范围明确、权威顺序清晰、目录结构具体、包含大量正反例,并且对版本、测试和性能都有项目化约束。
如果继续演进,我会优先做下面几件事。
1. 从“规范全集”收缩为“高价值决策集”
删除模型本就知道、且已由 ESLint 或 TypeScript 保证的常识,把上下文留给目录边界、项目例外、验证命令和真实踩坑点。
2. 拆分长篇参考内容
把功能模块结构、Vue 响应式陷阱、性能建议和注释规范拆成 references/,主文件保留路由规则,降低每次触发时的上下文成本。
3. 校正绝对化规则
检查每一个 MUST 和 NEVER 是否存在合理反例。能用条件表达的规则,就不要为了显得严格而写成绝对命令。
4. 增加仓库内的“活示例”
Skill 中已经指出参考模块,但还可以说明每个模块具体示范什么。参考路径必须定期验证,避免文件移动后变成失效说明。
5. 建立版本与构建验证
升级依赖时检查版本相关规则;对所有 TypeScript 和 Vue 示例做最小编译验证;对目录规范增加轻量检查脚本。
这不是否定已有内容,而是 Skill 从“有用的规则集合”走向“稳定的项目开发系统”时自然会经历的演进。
十四、一个可直接改造的前端项目 Skill 模板
下面这个骨架可以作为起点。它故意没有填入通用 Vue 知识,因为真正需要补充的,应该是你自己的项目答案。
---
name: project-frontend-development
description: 本项目的前端开发规范与工作流。用于新功能开发、功能重构、组件与状态设计、API 模块、目录和文件放置、测试及验证决策。涉及项目结构时作为权威来源。
---
# Project Frontend Development
## Authority
按以下顺序处理冲突:
1. 用户明确要求
2. 仓库 AGENTS.md (CLAUDE.md、copilot-instructions.md等)
3. 本 Skill
4. 其他专项 Skill
其他 Skill 可以优化实现细节,但不得改变本 Skill 定义的项目结构。
## Workflow
1. 阅读相关代码和代表模块。
2. 判断任务属于新功能、局部修改还是重构。
3. 选择适用的目录和实现规则。
4. 保持公开接口与无关行为不变。
5. 执行项目中真实存在的验证命令。
6. 总结改动、验证结果与剩余风险。
## Project Invariants
- [不可违反的项目约束]
- [公共契约与兼容性要求]
- [禁止引入的模式]
## Feature Structure
- [何时启用模块结构]
- [必需目录与按需目录]
- [相邻目录的职责边界]
- [提升到共享目录的条件]
## Implementation Decisions
- 请求与错误处理:[项目选择]
- 状态管理:[项目选择]
- 组件拆分:[判断标准]
- 类型放置:[判断标准]
- 样式与设计系统:[项目选择]
## Exceptions
- [遗留模块如何处理]
- [框架版本差异]
- [允许偏离规则的条件]
## Validation
- 运行:[项目实际命令]
- 保留并更新已有测试。
- 不声明未执行的检查已经通过。
## References
- 创建大型模块时读取 `references/feature-structure.md`。
- 修改 API 时读取 `references/api-conventions.md`。
- 处理高风险逻辑时读取 `references/testing-policy.md`。使用模板后,还应删除所有占位内容,只保留项目真正需要的章节。一个 80 行但每行都会影响决策的 Skill,通常比一个 800 行的前端知识百科更有效。
结语
为前端项目编写 Skill,本质上是在做一次“可执行的项目知识建模”。你需要把团队过去依赖口头传递、代码模仿和 Review 纠正的经验,转换成 AI 能够触发、检索、裁决和验证的规则。
最值得记住的不是某一种固定目录,也不是一定要写多少条规范,而是下面这条链路:
从真实任务发现决策点,从仓库事实提炼项目规则,用优先级解决冲突,用条件和示例消除歧义,用工具完成验证,再从失败案例中持续迭代。
当 Skill 能让 AI 在面对新需求时,不仅会写出正确的 Vue 代码,还能主动找到正确目录、沿用正确边界、克制无关重构并完成真实验证,它才真正成为了项目开发能力的一部分。
评论交流
支持作者