ECC `/vue-review` 全流程实战:Vue 3 代码审查的响应式、Composable、模板安全与性能检查清单
2026/9/8 21:17:35 网站建设 项目流程

ECC/vue-review全流程实战:Vue 3 代码审查的响应式、Composable、模板安全与性能检查清单

【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC

/vue-review是 ECC(The agent harness performance optimization system)提供的 Vue 专项代码审查命令,它负责调用vue-reviewer智能体,围绕 Composition API 正确性、响应式机制、composable 模式、模板安全、无障碍(a11y)与 Vue 特有性能问题展开审查。无论你正在合并 Vue PR、审计模板v-html/URL 绑定的安全性,还是验证一个新 composable 与 Pinia store 的正确性,本文都基于 commands/vue-review.md 及其配套源码,给出可复现的命令、分级检查清单与验收标准。读完你既可以独立完成一次/vue-review会话,也能把 CRITICAL/HIGH/MEDIUM 三级检查项固化进团队自己的 Vue 工程化流程。

命令做什么:一次/vue-review的完整生命周期

/vue-review不是"意见汇总",而是编排了一条可审计的流水线,文档中定义的五个步骤缺一不可:

  1. 识别 Vue 变更:通过git diff找出修改过的.vue文件,以及引入 Vue 依赖的.ts/.js文件;
  2. 运行 Lint:以eslint-plugin-vue执行eslint(工程如使用 flat config,应覆盖vue/vue3-recommended规则集);
  3. 类型检查:运行vue-tsc --noEmit或工程规范化的 typecheck 命令;
  4. 只审查 Vue 专属车道:响应式(reactivity)、composable、模板安全、无障碍、Vue 特有性能;
  5. 生成分级报告:按 CRITICAL / HIGH / MEDIUM 三个严重级别归类问题,输出结论。

对应的智能体定义位于 agents/vue-reviewer.md,其工具权限为Read, Grep, Glob, Bash,并且有明确的约束:只报告问题、不做重构改写。在拉取 PR 审查时,vue-reviewer 会先通过gh pr view --json baseRefName确认真实基线分支(不硬编码main),并在合并状态为红灯或存在冲突时先停手上报。这一"先确认仓库状态、再开始审查"的设计,保证了报告不会建立在一个过期的 diff 之上。

何时使用:适用范围与边界判断

文档明确列出适用场景:

  • PR 或 commit 触及.vue文件;
  • 编写或修改 Vue 组件、composable 或 Pinia store 之后;
  • 合并 Vue 代码之前;
  • 审计模板安全(v-html、URL 绑定);
  • 审查新 composable 的正确性;
  • 审计 Vue Router 守卫与导航;
  • 审查 Nuxt 服务端路由或 SSR 专属代码。

同时它划定了边界:.ts/.js变更且不引入任何 Vue 时,应改用/code-review(通用未提交变更/PR 审查)或直接调用typescript-reviewer。这一点在 agents/vue-reviewer.md 中也被复述为运行协议的一部分——先建立 diff 范围,若无.vue或 Vue 相关变更,则把现场交给typescript-reviewer并停止。

在 ECC 的命令注册与智能体路由中也保留了这个名称:可以在 COMMANDS-QUICK-REF.md 查到它的定位说明("Vue.js — Composition API correctness, reactivity, composable patterns, template security, accessibility, performance"),在 agent.yaml 中它同样作为命令入口被挂载。

/code-review、TypeScript 审查的分工

Vue 工程通常同时存在.vue与大量.ts/.js,为避免重复审查与结论冲突,ECC 通过"车道(lane)"模型切分责任,vue-review 文档给出如下对照:

工具审查范围
vue-reviewer(即本命令)响应式、composable、模板安全、a11y、Vue 性能、Pinia/Router
typescript-reviewer通用 TS/JS——any滥用、async 正确性、Node 安全
security-reviewer项目级安全审计
/code-review通用未提交变更或 PR 审查

在 agents/vue-reviewer.md 中这张分工表更细化为逐行对照:any滥用、as断言、strict-null 违例、Promise/async 正确性、innerHTML泛化 XSS 归typescript-reviewer;而响应式正确性、v-html/模板注入、composable 规则、props/emits/slots 契约、Vue Router 守卫、Pinia 模式、无障碍、v-memo/shallowRef/v-once、SSR 安全与v-forkey 稳定性则全部归vue-reviewer。因此文档要求:凡触及.vue的 PR,同时调用两个审查器,二者结论按设计不重叠

审查类别与分级检查清单(可复制的核心资产)

vue-review.md 将检查项收敛为三档。下面把命令文档与 vue-reviewer 智能体文档中的细节合并为可直接当 checklist 使用的清单。

CRITICAL(必须修复)

检查项为什么致命
v-html拼接未消毒的用户输入Vue 的文本插值{{ }}与属性绑定(:title)会自动转义,但v-html绕过转义,等价于 React 的dangerouslySetInnerHTML,是直接 XSS 向量
:href/:src绑定未校验的用户 URLjavascript:data:协议会直接执行代码;只应放行http/https/mailto
客户端 bundle 泄露密钥(VITE_*、NuxtpublicruntimeConfig)import.meta.env.VITE_*useRuntimeConfig().public内容都会随浏览器下发,任何 XSS 都可读取
Nuxt Nitro 服务端端点缺少输入校验server/api/server/routes/直接消费 body/query/params 而不做 schema 校验(如 zod/valibot)
localStorage/sessionStorage存会话令牌存储对一切 XSS 可见,应使用 httpOnly Cookie
Vue < 3.5 解构响应式 propsconst { title, count } = defineProps(...)拿到的是快照副本,不再响应;应改用toRefs()或经props.xxx访问
整体替换reactive()对象state = newState会破坏响应性(watcher 失效),应就地改属性或用Object.assign(state, newState)
watcher 源跟踪 ref 对象而非.valuewatch(() => myRef, ...)监听的永远是这个没变的 ref 容器;必须是watch(() => myRef.value, ...)

补充两个与版本相关的响应式要点(来自 vue-reviewer 智能体与 skills/vue-patterns/SKILL.md):Vue 3.5+ 已默认稳定启用 Reactive Props Destructure,解构变量自动响应,但不能直接watch(count, ...),会触发编译错误,必须用 getter 包装watch(() => count, ...)reactive()只对对象/数组有效,原始值请用ref()

HIGH(应当修复)

Composable 类

  • 模块作用域副作用:在setup/组件生命周期外初始化状态、启动定时器、订阅事件,副作用会在所有组件实例间共享;
  • 缺少清理:composable 内的watchwatchEffect、事件监听、interval、fetch 请求,必须在返回的 teardown 或onUnmounted中清理(Vue 3.5+ 可用onWatcherCleanup);
  • 接收响应式 ref 却只读一次.value存快照,源变化不再传导;
  • 返回普通对象/原始值而非ref/reactive/computed,消费方失去响应性;
  • 未以use前缀命名,破坏 lint 检测与 Vue 约定。

模板安全与正确性类

  • v-for:key;或:key="index"——重排/增删时状态挂到错误行,应用稳定数据库 ID;
  • 同一元素上同时使用v-if+v-for——v-if对每一项先求值,几乎总是逻辑错误,应改用<template v-for>内嵌v-if或 computed 过滤列表;
  • v-model绑定到无 setter 的 computed——用户输入被静默丢弃,必须同时提供getset
  • v-bind="$attrs"却未设inheritAttrs: false——属性同时落到根元素与被转发目标上。

组件架构类

  • 单文件组件超过 300 行(template+script),应拆分;
  • 直接修改 props(Vue 开发模式会告警),应通过defineEmits上抛或用v-model双向绑定;
  • 缺少 prop 校验(至少要有type,按需required/default);
  • 事件用 camelCase 命名(模板中建议 kebab-case);
  • document.querySelector/裸ref操作 DOM——应使用 template ref +useTemplateRef

Vue Router / Pinia / SSR(Nuxt)类

  • 路由守卫(beforeEnterbeforeEach)返回false却不提供跳转替代,用户被卡死,应重定向或给出原因;
  • 在 setup 顶层解构useRoute().params——同一组件内路由参数变化时解构拿到的是快照,应经toRefs(useRoute().params)computed()
  • Pinia 复杂业务变更散落在组件中——应收敛进 actions 或用分组$patch(),保持 devtools 时间线与状态流转可读;在 Pinia state 中存储非可序列化数据(SSR 水合与持久化会丢数据);
  • Nuxt 场景:无process.client守卫或onMounted直接用浏览器 API(window/document/localStorage会让服务端构建崩溃);useAsyncData/useFetchkey导致重复请求、缓存去重失效;用<ClientOnly>包裹 SEO 关键内容;漏写definePageMeta

MEDIUM(视情况考虑)

  • 新代码仍用 Options API / Mixins(Vue 3 生态已标准化于 Composition API 与 composable);
  • 组件超过 300 行、v-showv-if使用场景倒置(频繁切换用v-show,稀有/昂贵渲染用v-if);
  • <KeepAlive>:max,缓存无界增长;
  • 大体积整体替换数据未用shallowRefref()的深层响应化对整块替换的大数组/大对象开销高);
  • 非平凡表单手写校验而非 VeeValidate/FormKit 等成熟方案;
  • defineExpose暴露超出必要;
  • 使用v-bind="$attrs"时未关闭inheritAttrs
  • 有状态内容误用v-once导致显示陈旧;v-memo用在很少变化的列表(先 profile 再上);
  • 表单缺<form>+@submit.prevent<select>v-model:value、防抖用手写setTimeout而非useDebounceFn
  • Vue 3.5+ 用普通 ref 做模板引用,而非支持动态 id、类型更安全的useTemplateRef

自动化检查命令:可复制的执行集

vue-review 文档给出与 vue-reviewer 智能体几乎一致的诊断命令,接入 CI 或本地均可直接复用:

# Lint(必跑) npx eslint . --ext .vue,.ts,.js # Vue 专属类型检查 vue-tsc --noEmit # 定向安全规则 npx eslint . --rule 'vue/no-v-html: warn' \ --rule 'vue/no-template-target-blank: error' # 供应链检查 npm audit

vue-reviewer 智能体还补充了三条按项目约定收口的命令以及常用强化规则:

npm run typecheck --if-present # 尊重项目规范化命令 npx eslint . --rule 'vue/multi-word-component-names: error' npx eslint . --rule 'vue/require-default-prop: warn' npx prettier --check .

在 hooks 侧,rules/vue/hooks.md 给出了工程化落地建议:*.vue*.ts*.tsx文件保存后(PostToolUse)先按改动文件执行eslint --fixprettier --write,最后再跑项目级vue-tsc --noEmit(需要防抖/限定范围,避免每次击键保存拖垮编辑器)。要点是普通tsc读不懂.vueSFC,Vue 工程必须用vue-tsc;lint 走 flat config 的vue/vue3-recommended,格式化建议"Prettier 走 ESLint"避免双重格式化互搏。

文档还提示:若工程未配置eslint-plugin-vuevue-tsc,审查会把该缺口标为 HIGH 配置问题并继续执行,而不是中断整场审查。

一次真实的报告长什么样

vue-review.md 给出了完整的对话式示例,值得原样复刻成团队模板:

User: /vue-review Agent: # Vue Code Review Report ## Files Reviewed - src/components/UserCard.vue (modified) - src/composables/useUser.ts (new) - src/stores/useUserStore.ts (modified) ## Lint Results PASS: eslint clean PASS: vue-tsc clean ## Issues Found [CRITICAL] Unsanitized v-html File: src/components/UserCard.vue:15 Issue: User-controlled bio rendered as raw HTML via v-html. Why: XSS via stored script tags in user input. Fix: Sanitize with DOMPurify or render as text:

对应的修复示范(vue-review.md 原例):

<script setup> import DOMPurify from "dompurify"; const safeBio = computed(() => DOMPurify.sanitize(user.bio)); </script> <template> <div v-html="safeBio" /> </template>

v-html的约束在 rules/vue/security.md 中有更完整表述:Vue 只会自动转义文本插值{{ }}与动态属性绑定(如:title),下列向量不受保护——绝不把不可信内容当组件模板、禁止运行时的用户输入模板编译、警惕用户控制的:is;即使改用渲染函数或 scoped slot,把用户 HTML 传入h()innerHTML仍是换皮v-html,必须先消毒;:style绑定用户输入同样危险(CSS 数据渗出),应使用白名单属性的对象语法。推荐的工程惯例是在持久化前由后端完成消毒

第二个 HIGH 示例(composable watcher 清理):

watch(userId, async (newId, _old, onCleanup) => { const controller = new AbortController(); onCleanup(() => controller.abort()); const data = await fetch(`/api/users/${newId}`, { signal: controller.signal }); user.value = await data.json(); });

Vue 3.5+ 还提供了可在任意位置全局导入的onWatcherCleanup(),但它必须在 watcher 回调内同步调用

import { watch, onWatcherCleanup } from "vue"; watch(userId, async (newId) => { const controller = new AbortController(); onWatcherCleanup(() => controller.abort()); // ... fetch with signal });

报告结尾汇总三档计数并给出结论。vue-reviewer 智能体要求的每条 issue 固定四要素——[SEVERITY] 标题File: 文件路径:行号Issue: 一句话描述Why: 影响Fix: 具体改法,并附上总结表(Severity / Count / Status / Verdict),确保问题可定位、可评审、可回溯。

审批口径与团队落地

vue-review 的验收标准非常干脆:

状态条件
PASS: Approve无 CRITICAL 或 HIGH 问题
WARNING: Warning仅剩 MEDIUM 问题(谨慎合并)
FAIL: Block发现 CRITICAL 或 HIGH 问题

与其它命令的衔接顺序(供 CI 编排或手工流程复用):构建坏了先修构建 → 跑测试确认组件测试通过 → 合并 Vue 代码前跑/vue-review→ 同一 PR 的非 Vue 关注点交给/code-review

把 vue-review 的等级体系倒推进工程本身,就是一套可内化的质量门禁(quality gate):CRITICAL 对应 XSS、密钥泄露与响应性破坏,属于合并红线;HIGH 大多可用 lint 规则半自动拦截——这正是 rules/vue/coding-style.md 的价值,它把同一套纪律写成可执行的 SFC 结构规范(<script setup><template><style scoped>固定顺序)、响应式纪律(脚本内经.value变更、reactive对象不可整体重赋值、不经toRefs/storeToRefs的解构会静默丢响应性)、computed/watcher 纪律(computed 必须纯函数、watch 传 getter 而非裸对象、watchEffect 在首个await后停止追踪依赖)以及宏与模板纪律(每个v-for都要稳定唯一原始值 key、绝不同元素混用v-if+v-for)。

审查之外的自我延伸

vue-review.md 末尾给出了四条延伸路径,全部在仓库内可继续深挖:

  • Agent:agents/vue-reviewer.md——上文所有分级清单的完整源头,附 Prompt Defense Baseline(抵御越权/注入类提示词攻击)与输出格式契约;
  • Companion agent:agents/typescript-reviewer.md——Vue 相关 TS/JS 审查时并行运行;
  • Skills:skills/vue-patterns/SKILL.md——Vue 3 Composition API 正向模式库,含 Pinia setup store 全量示例、Router 守卫与响应式路由参数、NuxtuseAsyncData/useFetchkey 去重、NuxtruntimeConfig服务端/客户端切分、Vue 3.5+ 新 API(reactive props destructure、useTemplateRefonWatcherCleanupuseId<Teleport defer>hydrateOnVisible惰性水合);
  • Rules:rules/vue/ 目录——security.md、hooks.md、patterns.md(composable 输入用MaybeRefOrGetter统一toValue归一、vue-query 的 query key 必须放 ref 本体而非.value等反直觉要点)、coding-style.md、testing.md,共同构成可被 hook 在每次文件保存后自动触发的守门员。

换句话说,/vue-review是 ECC 把"资深 Vue 工程师审查心智"工程化的结果:命令定义流程、智能体给出分级专业判断、rules 把纪律变成 hook、skills 给出正面范式。实际使用只需在对话中发起/vue-review,然后在合并前依 PASS / WARNING / FAIL 三档收敛即可——它不替你写代码,但能让你带着同一套标准,把每次 Vue 合并的 XSS、响应性事故与隐藏性能债挡在 main 之外。

【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询