1. 为什么“一口气写完整个前端”是危险的幻觉?
Codex 这类代码生成模型,刚上手时确实让人头皮发麻——输入一句“用 Vue 写个带搜索和分页的商品列表页”,它真能甩出 300 行带组件、路由、API 调用、状态管理甚至基础样式的代码。我第一次看到时也激动得差点截图发朋友圈,结果第二天就删了:那堆代码跑不起来,改一行崩三处,测试全挂,构建报错像开盲盒,连npm run serve都卡在SyntaxError: Unexpected token 'export'上整整两小时。
这不是 Codex 不行,而是我们把“写代码”和“交付可运行、可维护、可测试的前端系统”混为一谈了。就像让一个顶级厨师只给你列满食材清单和火候描述,却不告诉你切菜顺序、锅具预热时间、收汁时机——你照着做,大概率炒糊一锅。Codex 是顶级食材+火候专家,但它不负责端盘子、不检查碗筷消毒、不处理客人投诉。前端工程真正的“端盘子”环节,恰恰藏在标题里那五个字里:Skills——不是技能点,是五组相互咬合、不可替代的工程能力模块。
这五组 Skills,我把它叫作“前端交付的五道闸门”:页面(UI/UX 实现)、逻辑(业务行为与状态流)、测试(质量守门员)、构建(交付流水线)、协作(人机协同协议)。它们不是并列关系,而是有严格依赖链:页面没定稿,逻辑没法对齐;逻辑没闭环,测试无从下手;测试没覆盖,构建不敢上线;构建没标准化,协作就是灾难。Codex 可以帮你快速冲过第一道闸门,但若强行让它替你闯完五道,结果不是效率翻倍,而是整条流水线在第三道闸口集体追尾。
你刷到的那些“Codex 10 分钟搞定电商首页”的视频,背后都藏着一个没露脸的资深前端,在镜头外花了 3 小时清理生成代码里的v-for嵌套陷阱、修复ref和reactive混用导致的响应式失效、重写被生成器硬塞进setup()里的this.$router.push、手动补全缺失的aria-label……这些工作,Codex 不会告诉你它没做,它只会安静地交出一份“看起来很完整”的代码。而真实项目里,80% 的返工成本,就埋在这份“完整”里。
所以标题说的“别让 Codex 一口气写完整个前端”,本质是提醒我们:把 Codex 当成一个超级高效的“分段执行器”,而不是一个黑箱交付引擎。它最擅长的,是在你明确划定边界后,精准填充某一段确定性高的内容——比如“根据这个 Figma 设计稿,生成符合 Ant Design Vue 规范的表单组件,包含校验规则和错误提示样式”,而不是“帮我做一个用户管理系统”。
这五组 Skills 的拆解,不是为了增加复杂度,恰恰是为了降低失控风险。当你把页面、逻辑、测试、构建、协作这五件事拆开定义、分别验收、独立迭代,Codex 才真正从“炫技玩具”变成“生产力杠杆”。接下来,我就用自己踩过的坑、压测过的配置、线上跑了一年半的真实项目数据,带你一层层拆开这五道闸门怎么设、怎么守、怎么让 Codex 在每一道里都干它最该干的活。
2. 页面 Skills:UI 实现不是“画出来就行”,而是设计语言的工程翻译
2.1 页面 Skills 的核心矛盾:设计稿像素级还原 ≠ 用户可交互体验
很多人以为页面 Skills 就是“把 Figma 或 Sketch 里的图切成 HTML/CSS”,这是最大误区。我见过最典型的反面案例:一个金融后台项目,Codex 根据高保真设计稿生成了所有按钮、卡片、表格,视觉还原度 98%,但上线后客服电话被打爆——老年用户根本找不到“导出 Excel”按钮。原因?设计稿里那个蓝色小图标,在生成代码里被写成了<i class="icon-export"></i>,没加任何文字标签,屏幕阅读器读不出,色弱用户也分辨不出。Codex 完美复刻了“形”,却完全忽略了“意”。
页面 Skills 的本质,是把设计语言翻译成可访问、可响应、可维护的工程实现。它包含三个不可割裂的子层:
- 语义层:HTML 元素是否准确表达内容意图(
<button>而非<div @click>,<nav>包裹导航,<time>标记日期); - 样式层:CSS 是否遵循 BEM 或 CSS-in-JS 的作用域隔离原则,关键动效是否有
prefers-reduced-motion降级; - 交互层:焦点管理是否合理(Tab 键顺序、模态框关闭后焦点回归)、键盘操作是否全覆盖(Enter/Space 触发、方向键切换)、加载态与空状态是否明确。
Codex 在语义层和样式层表现极佳,尤其当提示词明确指定框架规范时(如“使用 Vue 3 Composition API + Ant Design Vue 4.x,所有按钮必须用<a-button>组件,禁用原生<button>”)。但在交互层,它几乎必然失败——因为交互逻辑高度依赖业务上下文,而 Codex 看不到用户操作路径图(User Flow)和异常场景文档。
2.2 实操:用 Codex 生成页面组件的“三步锁定法”
我团队现在强制执行的页面生成流程,叫“三步锁定法”,确保 Codex 输出可控:
第一步:锁定设计约束(Design Constraints)
不直接扔设计稿链接,而是先人工提炼出 5 条硬性规则,写成提示词前置条件:
- 所有表单项必须支持无障碍访问:label 关联 input,错误信息用 aria-describedby 绑定 - 卡片组件最大宽度 1200px,移动端断点 768px,使用 rem 单位(根字体 16px) - 按钮禁用状态必须显示 cursor: not-allowed 且 opacity: 0.6 - 所有图标必须来自 @ant-design/icons-vue,禁止使用 font-awesome 或 SVG 内联 - 表格行 hover 效果仅限于鼠标悬停,禁用 touch 设备上的伪类这一步看似繁琐,实则省下后续 80% 的返工。Codex 对结构化约束响应极快,生成代码里aria-*属性和@ant-design/icons-vue导入几乎零错误。
第二步:锁定组件接口(Component Interface)
绝不让 Codex 自由发挥 props。我们提供标准接口定义:
// UserList.vue 接口契约 interface UserListProps { users: Array<{ id: string; name: string; status: 'active' | 'inactive' }>; loading: boolean; onUserClick: (id: string) => void; } interface UserListEmits { (e: 'update:users', value: typeof props.users): void; }Codex 生成的组件,必须严格实现此接口。我们用 TypeScript 的satisfies操作符做编译时校验,任何 props 名称或类型偏差都会报错。这逼它放弃“自作聪明”的命名(比如把onUserClick生成成handleUserSelect),保证组件可插拔。
第三步:锁定样式作用域(Style Scope)
强制要求所有样式必须包裹在<style scoped>内,且禁止使用!important。更关键的是,我们给 Codex 一个“样式原子库”:
- 主色:#1890ff(Ant Design primary) - 边框圆角:4px(统一所有卡片、按钮、输入框) - 阴影:box-shadow: 0 2px 8px rgba(0,0,0,0.1) - 字体:font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serifCodex 会老老实实套用这些值,不会擅自改成border-radius: 6px或box-shadow: 0 4px 12px #00000020。我们甚至发现,当明确指定“禁用 CSS 变量,全部用固定值”,生成的 CSS 文件体积比它自动生成的减少 37%,因为避免了冗余的--color-primary声明。
提示:Codex 对“禁止项”的理解远强于对“推荐项”。说“禁用
!important”比说“请谨慎使用!important”有效 10 倍。它的训练数据里,“禁止”是高频强约束信号。
2.3 页面 Skills 的避坑清单:那些 Codex 永远不会告诉你的细节
响应式陷阱:Codex 生成的媒体查询常写成
@media (max-width: 768px),但实际项目中,我们要求@media (max-width: 767.98px)。差 0.02px?iOS Safari 的视口计算会漏掉这个断点,导致 768px 宽度设备同时匹配 desktop 和 mobile 样式,布局错乱。这个细节,所有文档都不会提,但线上监控日志里,我们为此修过 3 次。字体渲染差异:Codex 默认用
font-smoothing: antialiased,但在 Windows Chrome 下会导致文字发虚。我们强制替换为-webkit-font-smoothing: subpixel-antialiased;,并加注释说明:“仅限 WebKit 内核,Firefox/Edge 无需设置”。这个补丁,是前端工程师用肉眼对比 12 种字体渲染效果后定的。图标对齐 bug:Ant Design Vue 的
<a-icon>在flex容器中默认align-items: flex-start,导致图标和文字基线不齐。Codex 生成的代码永远不加align-items: center。解决方案不是改全局样式,而是在每个用到图标的组件里,显式设置display: inline-flex; align-items: center;。我们把这个写进团队规范,Codex 生成时自然就带上了。
这些细节,没有一条出现在 Codex 的官方教程里。它们是真实项目里,用生产环境错误日志、用户反馈、性能监控数据一点点喂出来的。页面 Skills 的终极目标,不是“看起来像”,而是“用起来稳、读起来懂、改起来快”。
3. 逻辑 Skills:状态流不是“写 if-else”,而是业务规则的可验证契约
3.1 逻辑 Skills 的致命误区:把业务逻辑塞进组件,等于把发动机焊死在方向盘上
Codex 最爱干的一件事,就是把所有逻辑——从 API 请求、数据转换、权限校验到错误重试——一股脑塞进setup()函数里。生成的代码看着很“完整”,但实际是灾难现场。我拿一个真实的订单状态流转模块举例:Codex 生成的OrderDetail.vue里,onMounted中调用fetchOrder(),然后.then()里处理状态映射,.catch()里弹 Toast,再嵌套一个watch监听order.status去触发不同按钮显隐……整个逻辑像一团意大利面,耦合度爆表。
问题不在 Codex,而在我们没给它“逻辑分层”的指令。前端逻辑 Skills 的核心,是建立三层清晰的契约:
- 领域层(Domain Layer):纯函数,无副作用,只做业务规则计算(如
canCancelOrder(order: Order): boolean); - 应用层(Application Layer):协调领域逻辑与外部依赖(API、Storage、Router),处理副作用(如
cancelOrder(orderId: string): Promise<void>); - 表现层(Presentation Layer):仅负责状态映射与事件绑定(如
const { order, loading, cancelOrder } = useOrderDetail(orderId))。
这三层,对应着三种完全不同的测试策略、重构成本和协作方式。Codex 只适合生成领域层和应用层的骨架,表现层必须由人手写——因为只有人才知道哪个状态该触发哪个 UI 动效、哪个错误该展示哪种用户提示。
3.2 实操:用 Codex 生成领域逻辑的“契约驱动法”
我们给 Codex 的提示词,从来不是“写个订单取消逻辑”,而是提供一份可执行的契约文档:
【领域契约】订单取消规则(v2.3) - 规则1:订单状态为 'pending' 或 'confirmed' 时允许取消 - 规则2:订单创建时间超过 72 小时,禁止取消 - 规则3:若订单含预售商品,需额外校验预售结束时间(预售结束时间 > 当前时间) - 规则4:取消后,订单状态变为 'cancelled',并记录取消原因 - 输出要求:生成 TypeScript 模块,导出 pure function canCancelOrder,接收 Order 类型参数,返回 boolean - Order 类型定义:interface Order { id: string; status: 'pending' | 'confirmed' | 'shipped' | 'cancelled'; createdAt: string; items: Array<{ isPresale: boolean; presaleEndTime: string }> }Codex 生成的canCancelOrder.ts,我们直接放进src/domain/order/目录。它生成的代码,几乎 100% 符合契约:
export function canCancelOrder(order: Order): boolean { if (!['pending', 'confirmed'].includes(order.status)) return false; const createdTime = new Date(order.createdAt); const now = new Date(); if (now.getTime() - createdTime.getTime() > 72 * 60 * 60 * 1000) return false; if (order.items.some(item => item.isPresale && new Date(item.presaleEndTime) <= now)) return false; return true; }注意,它没写任何console.log,没调 API,没改状态——纯粹的、可单元测试的、无副作用的函数。这才是领域逻辑该有的样子。
接着,我们用同样的契约驱动法,生成应用层:
【应用契约】订单取消服务(v2.3) - 输入:orderId: string, reason: string - 输出:Promise<void> - 步骤1:调用 canCancelOrder 校验(传入 fetchOrder(orderId) 获取的订单数据) - 步骤2:校验通过后,调用 POST /api/orders/{id}/cancel,body 包含 reason - 步骤3:成功后 dispatch 'ORDER_CANCELLED' 事件,失败时 throw 标准化错误(code: 'ORDER_CANCEL_FAILED') - 输出要求:生成 Composable 函数 useOrderCancellation,返回 { cancel, loading, error }Codex 生成的useOrderCancellation.ts,我们放进src/composables/order/。它会自动 importcanCancelOrder和fetchOrder,结构清晰,错误处理规范。
注意:我们从不生成
useOrderCancellation的内部实现细节(如try/catch块怎么写),只定义契约。Codex 会按约定填充,且代码质量远高于人工手写——因为它的训练数据里,有百万级高质量 Composable 示例。
3.3 逻辑 Skills 的实测数据:契约驱动如何降低 63% 的逻辑 Bug
我们对过去 6 个月的线上 Bug 做了归因分析,发现 63% 的逻辑类故障,源于“契约模糊”:
- 开发 A 认为“订单超时 24 小时可取消”,开发 B 实现时按“72 小时”;
- 测试用例覆盖了
status === 'pending',但漏了status === 'confirmed'; - 新增预售商品类型后,没人更新取消校验逻辑。
引入契约驱动法后,所有领域规则必须写进 Markdown 契约文档(存 Git),Codex 生成代码必须通过契约校验(CI 脚本自动运行tsc --noEmit && jest --testPathPattern=domain/),否则 PR 不通过。结果:
- 领域逻辑相关 Bug 下降 63%(从月均 12.4 个降至 4.6 个);
- 新成员熟悉订单取消逻辑的时间,从 3 天缩短至 2 小时(直接读契约文档 + 运行单元测试);
- 第三方系统对接时,只需提供契约文档,对方就能生成兼容的调用代码,无需反复对齐。
逻辑 Skills 的价值,不在于写得多快,而在于让业务规则变得可审计、可追溯、可自动化验证。Codex 是最好的契约执行者,但契约本身,必须由人来定义。
4. 测试 Skills:不是“写 test case”,而是构建质量防火墙的四层纵深防御
4.1 测试 Skills 的真相:80% 的测试代码,根本不该由 Codex 生成
网上很多教程教你怎么用 Codex 自动生成 Jest 测试用例,听着很酷,实际是饮鸩止渴。我试过让 Codex 为一个 200 行的useCartComposable 生成测试,它产出 15 个it块,覆盖了所有方法调用,但其中 12 个测试用例在真实场景中毫无意义——比如测试addItem时 mock 了一个永远不会发生的cart.items.length > 999边界条件,却漏掉了最关键的“添加重复商品时数量累加而非新增条目”逻辑。
测试 Skills 的核心,不是覆盖率数字,而是构建四层纵深防御体系:
- 单元层(Unit):验证单个函数/Composable 的输入输出契约(领域层、应用层);
- 集成层(Integration):验证多个 Composable 协同工作的状态流(如
useCart+useUser+usePayment); - 组件层(Component):验证 UI 组件在不同状态下的渲染正确性与交互响应(Vitest + Vue Test Utils);
- E2E 层(End-to-End):验证真实用户旅程(Playwright,覆盖跨页面、网络延迟、异常中断)。
Codex 只在单元层有可靠价值——因为单元测试的输入输出契约最清晰。其他三层,它生成的测试要么太浅(只测渲染,不测状态变更),要么太假(mock 数据脱离真实业务场景),反而污染测试套件。
4.2 实操:单元测试的“契约反向生成法”
我们的单元测试不靠 Codex “生成”,而是用“契约反向生成”:
先写契约文档(同逻辑 Skills):
【单元测试契约】canCancelOrder - 场景1:status = 'pending', createdAt = '2023-01-01T00:00:00Z' → 返回 true - 场景2:status = 'shipped' → 返回 false - 场景3:createdAt 超过 72 小时 → 返回 false - 场景4:含预售商品且 presaleEndTime 已过期 → 返回 false - 场景5:含预售商品但 presaleEndTime 未过期 → 返回 true用 Codex 把契约转成测试用例:
根据以上契约,生成 Vitest 测试文件 canCancelOrder.spec.ts,使用 describe/it 结构,每个场景一个 it 块,使用 expect().toBe(true/false) 断言
Codex 输出的测试代码,我们几乎不用改:
import { canCancelOrder } from '@/domain/order/canCancelOrder'; import { Order } from '@/domain/order/types'; describe('canCancelOrder', () => { it('returns true for pending order within 72 hours', () => { const order: Order = { id: '1', status: 'pending', createdAt: '2023-01-01T00:00:00Z', items: [] }; expect(canCancelOrder(order)).toBe(true); }); it('returns false for shipped order', () => { const order: Order = { id: '2', status: 'shipped', createdAt: '2023-01-01T00:00:00Z', items: [] }; expect(canCancelOrder(order)).toBe(false); }); // ... 其他场景 });关键点在于:测试用例的数据,必须来自真实业务场景,而非 Codex 想象。我们有一个内部工具,从生产数据库脱敏抽取 1000 个典型订单样本,按状态、时间、商品类型分类,作为测试数据源。Codex 只负责把“场景描述”翻译成代码,数据本身是真实的。
4.3 四层防御的实操配置:让测试真正成为质量守门员
单元层(Vitest):
CI 中强制要求vitest run --coverage --threshold-lines 85%。但阈值不是拍脑袋定的——我们统计了过去一年所有被线上 Bug 触发的单元测试,发现 85% 覆盖率能捕获 92% 的逻辑缺陷,再往上投入产出比急剧下降。--threshold-lines比--threshold-branches更实用,因为前端逻辑的分支复杂度远低于行数复杂度。集成层(Vitest + Mock Service Worker):
我们用 MSW 拦截所有 API 请求,模拟真实后端响应。Codex 不生成这些 mock,但我们提供标准模板:// mocks/handlers.ts import { rest } from 'msw'; export const handlers = [ rest.get('/api/orders/:id', (req, res, ctx) => { // 返回预设的 5 种订单状态 JSON return res(ctx.status(200), ctx.json(getOrderMock(req.params.id))); }) ];Codex 只需按模板填充
getOrderMock的返回值,确保覆盖所有状态组合。组件层(Vitest + Vue Test Utils):
禁用mount的global.config全局配置,每个测试文件显式声明plugins和components。Codex 生成的组件测试,必须包含:props的所有合法/非法值组合;emits的所有事件触发场景;slots的默认/具名插槽渲染;v-model的双向绑定验证。 我们有个检查脚本,扫描所有*.spec.ts,确保每个it块至少包含expect(wrapper.html()).toContain(...)和await wrapper.trigger('click')。
E2E 层(Playwright):
所有 E2E 测试基于真实用户旅程录制(Playwright Codegen),而非 Codex 编写。我们只用 Codex 做一件事:把录制的.spec.ts文件,按业务模块自动拆分成checkout-flow.spec.ts、user-profile-flow.spec.ts等,并添加标准的test.describe.configure({ mode: 'parallel' })。它让 E2E 测试从 47 分钟缩短到 12 分钟,因为并行执行不再需要人工拆分。
提示:测试 Skills 的最大心得——永远用真实数据驱动测试,用自动化工具保障执行,用 Codex 只做机械性翻译。人负责定义“什么值得测”,机器负责“怎么高效测”。
5. 构建 Skills:不是“配 webpack”,而是定义可重复、可审计、可回滚的交付契约
5.1 构建 Skills 的认知革命:构建不是技术活,是交付承诺的工程化
很多人觉得构建 Skills 就是调vue-cli或vite的配置,改改build.rollupOptions。这是把构建当成装修——只管墙面刷白、地板铺平。真正的构建 Skills,是定义交付契约:每次npm run build执行后,你承诺交付给运维、CDN、测试团队的,到底是什么?
这个契约包含四个维度:
- 产物维度:生成哪些文件?
dist/下必须有index.html、assets/、public/的精确映射; - 元数据维度:
package.json的version、buildInfo字段(含 Git commit hash、构建时间、CI Job ID); - 质量维度:产物大小(
dist/assets/*.js< 150KB)、Lighthouse 性能分(≥90)、无console.error残留; - 安全维度:
Content-Security-Policy头、Subresource Integrity校验、无已知高危漏洞(npm audit --audit-level high)。
Codex 可以帮你生成vite.config.ts,但它无法承诺“这次构建的产物,能在 AWS CloudFront 上 100% 缓存命中”。构建 Skills 的核心,是把这四个维度,变成可编程、可验证、可审计的代码。
5.2 实操:构建契约的“四维校验清单”
我们所有项目的vite.config.ts,都基于一个 Codex 生成的模板,但关键在于后续的四维校验:
维度1:产物校验(Post-Build Hook)
在build.end钩子中,运行自定义脚本:
// plugins/validate-dist.ts export function validateDistPlugin() { return { name: 'validate-dist', async buildEnd() { const distDir = path.resolve(__dirname, '../dist'); const htmlFile = path.join(distDir, 'index.html'); const assetsDir = path.join(distDir, 'assets'); // 校验 HTML 必须存在且含 CSP meta const html = fs.readFileSync(htmlFile, 'utf8'); if (!html.includes('<meta http-equiv="Content-Security-Policy"')) { throw new Error('Missing CSP in index.html'); } // 校验 assets 下 JS 文件大小 const jsFiles = await glob('*.js', { cwd: assetsDir }); for (const file of jsFiles) { const size = fs.statSync(path.join(assetsDir, file)).size; if (size > 150 * 1024) { // 150KB throw new Error(`Asset ${file} exceeds 150KB: ${size}`); } } } }; }Codex 生成这个插件时,我们只给它提示词:“写一个 Vite 插件,在 build.end 钩子中校验 dist/index.html 是否含 CSP meta,且 dist/assets/ 下所有 .js 文件小于 150KB,超限则 throw Error”。它生成的代码,我们直接放进vite.config.ts的plugins数组。
维度2:元数据注入(Build Info Plugin)
我们用vite-plugin-build-info注入构建信息,但关键在 Codex 生成的buildInfo.ts:
// src/utils/buildInfo.ts export const buildInfo = { version: process.env.npm_package_version || 'dev', commit: process.env.GIT_COMMIT_HASH || 'unknown', timestamp: new Date().toISOString(), ciJobId: process.env.CI_JOB_ID || 'local' };Codex 生成这个文件时,我们强调:“必须从环境变量读取,禁止硬编码,且所有字段提供 fallback 值”。它生成的代码,我们直接import { buildInfo }到main.ts,并在 Vue app 的provide中注入,供所有组件读取。
维度3:质量扫描(Lighthouse CI)
我们不把 Lighthouse 当本地工具,而是集成进 CI:
# .github/workflows/build.yml - name: Run Lighthouse Audit uses: treosh/lighthouse-ci-action@v9 with: urls: | https://staging.example.com/ uploadArtifacts: true temporaryPublicStorage: true budgetFile: lighthouse-budget.jsonlighthouse-budget.json由 Codex 生成:
根据 Lighthouse v10.0 最佳实践,生成 budget 文件,要求:performance >= 90, accessibility >= 95, best-practices >= 90, seo >= 90, pwa >= 85Codex 输出的 JSON,我们直接提交到仓库,CI 用它做阈值校验。
维度4:安全扫描(Trivy + npm audit)
在 CI 的build步骤后,加两行命令:
# 扫描 node_modules 安全漏洞 npm audit --audit-level high --json > audit-report.json # 扫描 Docker 镜像(如果用 Docker 部署) trivy fs --security-checks vuln --format json . > trivy-report.json报告生成后,用 Codex 写解析脚本:
写一个 Node.js 脚本,读取 audit-report.json,提取 high/critical 级别漏洞数量,若 > 0 则 exit 1它生成的脚本,我们放进scripts/audit-check.js,CI 中node scripts/audit-check.js。
5.3 构建 Skills 的血泪教训:一次未校验的构建,引发 72 小时 P0 故障
去年双十一前,一个新同学跳过构建校验步骤,直接npm run build后上传产物。问题出在维度1:他本地vite.config.ts里注释掉了validateDistPlugin,但没删插件代码。构建产物里,index.html缺少 CSP meta,导致 CDN 缓存了不安全的 HTML。攻击者利用 XSS 注入恶意脚本,窃取了 327 个用户的支付信息。
事后复盘,我们发现三个致命疏漏:
- 构建校验插件没设为
enforce: 'pre',导致它在buildEnd钩子中执行,但产物已生成; npm run build命令没加--strict参数,无法阻止带警告的构建;- CI 流程里,
validateDistPlugin的校验步骤被放在deploy阶段,而非build阶段。
现在,我们的构建契约强制:
- 所有校验插件
enforce: 'pre',在产物生成前拦截; npm run build别名改为npm run build:strict,内含--strict;- CI 的
build阶段必须包含vite build --mode production和node scripts/validate-dist.js两个步骤,缺一不可。
构建 Skills 的终极目标,不是“让代码跑起来”,而是“让交付过程可预测、可审计、可回滚”。Codex 是最好的契约执行者,但契约本身,必须由人来定义、由流程来保障。
6. 协作 Skills:不是“用好 Codex”,而是建立人机协同的 SOP 与责任边界
6.1 协作 Skills 的本质:定义“谁在什么时候,对什么负责”
所有前端团队都在用 Codex,但只有少数团队真正解决了协作问题。我们曾走过弯路:让 Codex 生成的代码,直接进主分支。结果是,Code Review 变成“找 Codex 的错”,PR 描述全是“AI 生成,请检查”,Reviewers 陷入“信不信它”的哲学困境,最终演变成“反正它写的,出了问题算它的”——这违背了工程责任制的根本。
协作 Skills 的核心,是建立人机协同的 SOP(Standard Operating Procedure),明确五个关键责任点:
- 提示词工程师(Prompt Engineer):负责将需求转化为 Codex 可执行的契约(设计约束、逻辑契约、测试契约、构建契约),输出
.prompt.md文件; - AI 生成者(AI Generator):执行 Codex,生成代码,提交 PR,PR 标题必须含
[AI]前缀; - 人类校验者(Human Verifier):对 PR 做三重校验——契约符合性(是否按
.prompt.md实现)、工程规范性(是否符合团队 ESLint/Prettier)、业务合理性(逻辑是否符合真实场景); - 测试守护者(Test Guardian):运行全部测试套件,验证覆盖率、E2E 通过率、Lighthouse 分,出具
test-report.md; - 发布决策者(Release Decider):综合校验报告、测试报告、线上灰度数据,决定是否合并。
这五个人,可以是同一个人,但职责必须分离。Codex 永远只是“生成者”,它不参与校验、不参与测试、不参与决策。
6.2 实操:协作 SOP 的落地工具链
我们用 GitHub Actions + 自定义 Bot 实现 SOP 自动化:
Step 1:提示词校验(Prompt Linter)
当 PR 提交时,Bot 自动扫描*.prompt.md文件,检查是否包含:
- 设计约束(Design Constraints)章节;
- 逻辑契约(Logic Contract)章节;
- 测试契约(Test Contract)章节;
- 构建契约(Build Contract)章节;
- 所有契约必须有版本号(v1.0)和最后更新时间。
缺失任一项,Bot 评论:“⚠️ 提示词不完整,请补充 [缺失章节] 后重试”。
Step 2:AI 生成代码校验(AI Code Linter)
Bot 运行自定义脚本,检查生成代码是否:
- 所有
import语句是否来自@/domain/、@/composables/等约定路径; - 是否存在
console.log、debugger、any类型; - 是否所有
v-if都有对应的v-else或注释说明; - 是否所有 API 调用都经过
useApiComposable 封装。
违反任一项,Bot 评论:“❌ 生成代码不符合工程规范,请修正”。
Step 3:自动化测试网关(Auto-Test Gateway)
Bot 触发 CI 流水线,运行:
vitest run --coverage(单元测试);vitest run --environment jsdom(组件测试);playwright test --project=chromium(E2E);lighthouse https://staging.example.com --output=lh-report.json --quiet --chromeFlags="--headless=new"(性能扫描)。
所有测试通过且覆盖率 ≥85%,Bot 评论:“✅ 自