commands/vue-review.md
This command invokes the vue-reviewer agent for Vue-specific code review. For pull requests touching .vue files or Vue-containing .ts/.js files, both vue-reviewer and typescript-reviewer should run — each owns a distinct lane.
.vue files and Vue-related .ts/.js files via git diffeslint with eslint-plugin-vuevue-tsc --noEmit or the project's canonical typecheck commandUse /vue-review when:
.vue filesv-html, URL bindings)For pure .ts/.js changes with no Vue imports, use /code-review (general) or invoke typescript-reviewer directly.
/code-review and TypeScript Review| Tool | Scope |
|---|---|
vue-reviewer (this command) | Reactivity, composables, template security, a11y, Vue performance, Pinia/Router |
typescript-reviewer | Generic TS/JS — any abuse, async correctness, Node security |
security-reviewer | Project-wide security audit |
/code-review | Generic uncommitted-changes or PR review |
On a .vue / Vue-related PR, invoke both vue-reviewer and typescript-reviewer. Findings from each are non-overlapping by design.
v-html with unsanitized input:href/:src with unvalidated user URLs (javascript:, data:)VITE_*, Nuxt public runtimeConfig)localStorage/sessionStorage for session tokensreactive() object replacement (breaks watchers).valuev-for without :key or with key={index}v-if + v-for on same elementuseRoute().params destructured at top-level (snapshot)v-model bound to computed without setterv-show where v-if is more appropriate (or vice versa):max on <KeepAlive>shallowRef for large replaced datadefineExpose exposing more than necessaryinheritAttrs not disabled when using v-bind="$attrs"# Lint (required)
npx eslint . --ext .vue,.ts,.js
# Vue-specific typecheck
vue-tsc --noEmit
# Targeted security rules
npx eslint . --rule 'vue/no-v-html: warn' \
--rule 'vue/no-template-target-blank: error'
# Supply-chain
npm audit
If eslint-plugin-vue or vue-tsc is not configured, the review will flag the gap as a HIGH config issue and continue.
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
<script setup>
import DOMPurify from "dompurify";
const safeBio = computed(() => DOMPurify.sanitize(user.bio));
</script>
<template>
<div v-html="safeBio" />
</template>
```
[HIGH] Watcher in composable missing cleanup
File: src/composables/useUser.ts:22
Issue: `watch` callback fires fetch without AbortController; stale responses can overwrite newer data.
Fix: Use onCleanup to abort:
```ts
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();
});
```
## Summary
- CRITICAL: 1
- HIGH: 1
- MEDIUM: 0
Recommendation: FAIL: Block merge until CRITICAL issue is fixed
| Status | Condition |
|---|---|
| PASS: Approve | No CRITICAL or HIGH issues |
| WARNING: Warning | Only MEDIUM issues (merge with caution) |
| FAIL: Block | CRITICAL or HIGH issues found |
/vue-review before merging Vue code/code-review for non-Vue-specific concerns on the same PRagents/vue-reviewer.mdagents/typescript-reviewer.md (run alongside for Vue-related TS/JS)skills/vue-patterns/rules/vue/