Vue 3 Expert
Vue 3 Composition API patterns, Pinia, reactivity, component design, forms, and performance.
Use npx chub search vue for relevant documentation packages within the Context Hub
When to Use
Auto-activate on: .vue files, Vue 3 Composition API, Pinia stores, <script setup>, Vue Router, composables
Explicit: /mk:vue [concern]
Do NOT invoke for: TypeScript fundamentals (use mk:typescript), visual design (use mk:frontend-design), testing (use mk:testing)
Workflow Integration
Operates in Phase 3 (Build GREEN). Output supports the developer agent.
Process
- Detect concern — component? composable? store? form? performance?
- Load relevant reference — vue-patterns, pinia, or forms
- Apply patterns — implement using Vue 3 best practices from references
- Verify — component renders, types pass, no console warnings
Core Rules (always apply)
- ALWAYS use
<script setup lang="ts">— never Options API - ALWAYS use
definePropswith TypeScript interfaces — never runtime validation - ALWAYS use
storeToRefs()when destructuring Pinia store state - NEVER use
v-htmlwith user content (security-rules.md — XSS vector) - PREFER composables (
use*) over mixins - PREFER
ref()for primitives,reactive()only for complex objects - NAME components PascalCase, files kebab-case (
agent-conduct.md(B1))
Anti-Patterns
| Don't | Do Instead | | ---------------------------------- | -------------------------------- | | Options API (data(), methods:) | Composition API <script setup> | | this.$store / Vuex | Pinia with setup store syntax | | Direct store state destructuring | storeToRefs(useMyStore()) | | v-html with dynamic content | v-text or sanitized rendering | | reactive() for primitives | ref() for primitives | | Watchers when computed works | computed() for derived state | | Global event bus | provide/inject or Pinia | | defineComponent() wrapper | <script setup> directly |
Output Format
## Vue: {concern}
**Files:** {list of .vue files modified}
**Pattern:** {composition API | pinia store | composable | component}
### Implementation
{code changes with Vue 3 patterns applied}
### Verification
{component renders, no console warnings, types pass}
References
| Reference | When to load | Content | | --------------------------------------------------- | ------------------------- | ---------------------------------------------------------- | | [vue-patterns.md](./references/vue-patterns.md) | Component/composable work | Composition API, reactivity, component design, performance |
Failure Handling
| Failure | Recovery | | ----------------------------------- | ------------------------------------------- | | Vue 2 syntax detected (Options API) | Migrate to Composition API <script setup> | | Pinia not installed | npm install pinia | | Type errors in template | Fix with defineProps<T>() typing |
Gotchas
- Destructuring
reactive()loses reactivity —const { count } = reactive({ count: 0 })makescounta plain number; always usetoRefs()or keep the reactive object intact, or switch toref(). storeToRefs()not called when destructuring Pinia store —const { user } = useAuthStore()gives a non-reactive snapshot;const { user } = storeToRefs(useAuthStore())is required for reactive bindings.<script setup>withdefineExpose()is required for parentrefaccess — callingchildRef.value.method()from a parent always returnsundefinedunless the child explicitlydefineExpose({ method }); omitting this is silent until runtime.:deep()selector broken when component uses scoped styles + slot content — slot content comes from the parent scope, so:deep(.child-class)in a scoped style block has no effect on slotted content; use:slotted(.child-class)instead.watchEffectcleanup race on fast re-renders — without calling theonCleanupcallback to cancel async operations, a fast prop change triggers a second effect before the first resolves, causing stale state writes; always register cleanup viawatchEffect((onCleanup) => { onCleanup(() => controller.abort()) }).- Pinia store state not hydrated in SSR (Nuxt/Vite SSR) — calling
useMyStore()outside a component setup context (e.g., in a top-level module) creates a store instance disconnected from the SSR app; always call stores insidesetup()or pass thepiniainstance explicitly viauseMyStore(pinia).