Skill: ivangdavila/vue (version 1.0.1)

--- name: Vue slug: vue version: 1.0.1 description: Build Vue 3 applications with Composition API, proper reactivity patterns, and production-ready components. metadata: {"clawdbot":{"emoji":"💚","requires":{"bins":["node"]},"os":["linux","darwin","win32"]}} --- ## When to Use User needs Vue expertise — from Composition API patterns to production optimization. Agent handles reactivity, component design, state management, and performance. ## Quick Reference | Topic | File | |-------|------| | Reactivity patterns | `reactivity.md` | | Component patterns | `components.md` | | Composables design | `composables.md` | | Performance optimization | `performance.md` | ## Composition API Philosophy - Composition API is not about replacing Options API—it's about better code organization - Group code by feature, not by option type—related logic stays together - Extract reusable logic into composables—the main win of Composition API - `<script setup>` is the recommended syntax—cleaner and better performance ## Reactivity Traps - `ref` for primitives—access with `.value` in script, auto-unwrapped in template - `reactive` can't reassign whole object—`state = {...}` breaks reactivity - Destructuring `reactive` loses reactivity—use `toRefs(state)` to preserve - Array index assignment reactive in Vue 3—`arr[0] = x` works, unlike Vue 2 - Nested refs unwrap inside reactive—`reactive({count: ref(0)}).count` is number, not ref ## Watch vs Computed - `computed` for derived state—cached, recalculates only when dependencies change - `watch` for side effects—when you need to DO something in response to changes - `computed` should be pure—no side effects, no async - `watchEffect` for immediate reaction with auto-tracked dependencies ## Watch Traps - Watching reactive object needs `deep: true`—or watch a getter function - `watch` is lazy by default—use `immediate: true` for initial run - Watch callback receives old/new—`watch(source, (newVal, oldVal) => {})` - `watchEffect` can't access old value—use `watch` if you need old/new comparison - Stop watchers with returned function—`const stop = watch(...); stop()` ## Props and Emits Traps - `defineProps` for type-safe props—`defineProps<{ msg: string }>()` - Props are readonly—don't mutate, emit event to parent - `defineEmits` for type-safe events—`defineEmits<{ (e: 'update', val: string): void }>()` - `v-model` is `:modelValue` + `@update:modelValue`—custom v-model with `defineModel()` - Default value for objects must be factory function—`default: () => ({})` ## Template Ref Traps - `ref="name"` + `const name = ref(null)`—names must match exactly - Template refs available after mount—access in `onMounted`, not during setup - `ref` on component gives component instance—`ref` on element gives DOM element - Template ref with `v-for` becomes array of refs ## Lifecycle Traps - `onMounted` for DOM access—component mounted to DOM - `onUnmounted` for cleanup—subscriptions, timers, event listeners - `onBeforeMount` runs before DOM insert—rarely needed but exists - Hooks must be called synchronously in setup—not inside callbacks or conditionals - Async setup needs `<Suspense>` wrapper ## Provide/Inject Traps - `provide('key', value)` in parent—`inject('key')` in any descendant - Reactive if value is ref/reactive—otherwise static snapshot - Default value: `inject('key', defaultVal)`—third param for factory function - Symbol keys for type safety—avoid string key collisions ## Vue Router Traps - `useRoute` for current route—reactive, use in setup - `useRouter` for navigation—`router.push('/path')` - Navigation guards: `beforeEach`, `beforeResolve`, `afterEach`—return `false` to cancel - `<RouterView>` with named views—multiple views per route ## Common Mistakes - `v-if` vs `v-show`—v-if removes from DOM, v-show toggles display - Key on `v-for` required—`v-for="item in items" :key="item.id"` - Event modifiers order matters—`.prevent.stop` vs `.stop.prevent` - Teleport for modals—`<Teleport to="body">` renders outside component tree

path: components.md
content: # Component Patterns

## Props Best Practices

- Type your props: `defineProps<{msg: string, count?: number}>()`
- Required props have no `?`—TypeScript enforces
- Default values: `withDefaults(defineProps<Props>(), {count: 0})`
- Props are readonly—never mutate, emit event to parent instead

## Emit Patterns

- Type your emits: `defineEmits<{(e: 'update', value: string): void}>()`
- Emit returns boolean if event handler returns false
- Vue 3.3+ shorthand: `defineEmits<{update: [value: string]}>()`
- Always emit for changes—maintain one-way data flow

## v-model Patterns

- `v-model` = `:modelValue` + `@update:modelValue`
- Multiple v-model: `v-model:title`, `v-model:content`—different props
- `defineModel()` (3.4+) creates ref that syncs automatically—much simpler
- v-model modifiers: `.trim`, `.number`, `.lazy`—access via `modelModifiers`

## Slots Patterns

- Default slot: `<slot></slot>`—or `<slot>fallback content</slot>`
- Named slots: `<slot name="header">` + `<template #header>`
- Scoped slots: `<slot :item="item">` + `<template #default="{item}">`
- `$slots.header?.()` to check if slot provided

## Dynamic Components

- `<component :is="componentName">`—switch between components
- `<KeepAlive>` preserves state when switching—cached in memory
- `include`/`exclude` props on KeepAlive—control which are cached
- `max` prop limits cache size—LRU eviction

## Async Components

- `defineAsyncComponent(() => import('./Comp.vue'))`—lazy loading
- Loading component: `loadingComponent` option—shown while loading
- Error component: `errorComponent` option—shown on load failure
- Combine with `<Suspense>` for coordinated loading states

## Teleport

- `<Teleport to="body">`—render content outside component tree
- Useful for modals, dropdowns, tooltips—need to escape overflow/z-index
- `disabled` prop for conditional teleporting
- Events still bubble in Vue component tree—not DOM tree

## Provide/Inject

- `provide('key', value)` in ancestor—available to all descendants
- `inject('key', defaultValue)` to receive
- Provide reactive value for reactive inject—`provide('count', ref(0))`
- Symbol keys for type safety—avoid string collisions


path: composables.md
content: # Composables Design

## Composable Philosophy

- Composables are functions that encapsulate stateful logic
- Name with `use` prefix—`useMouse`, `useAuth`, `useFetch`
- Return refs/reactive, not plain values—caller needs reactivity
- Composables are like custom hooks in React

## Basic Structure

```javascript
export function useCounter(initial = 0) {
  const count = ref(initial)
  const increment = () => count.value++
  const decrement = () => count.value--
  return { count, increment, decrement }
}
```

## Input Flexibility

- Accept ref OR plain value as input—support both use cases
- `toValue()` (3.3+) unwraps ref or returns value—flexible API
- For reactive objects, consider accepting getter function
- Document what inputs are accepted

## Return Value Patterns

- Return object with named properties—allows destructuring what's needed
- Return refs, not reactive—easier to destructure
- Return methods along with state—complete API
- Consider returning readonly for state—prevent external mutation

## Lifecycle in Composables

- `onMounted`, `onUnmounted` work inside composables—attached to calling component
- Cleanup with `onUnmounted`—unsubscribe, clear timers
- Composable must be called synchronously in setup—not in callbacks
- Multiple components using same composable = separate instances

## Side Effects

- Start effects in composable—they run when component mounts
- Clean up in `onUnmounted`—or use cleanup function in watchEffect
- Consider `onScopeDispose` for effect scope cleanup
- Return stop functions for manual control

## Async Composables

- Return reactive state that updates when async completes
- Include loading and error states—`{data, isLoading, error}`
- Consider `useFetch` pattern from VueUse
- For SSR, handle hydration mismatch

## Composition Patterns

- Composables can use other composables—build on abstractions
- Avoid deep nesting—keep composables focused
- Share types between composables—consistent API
- Consider extracting to separate packages—if truly reusable

## VueUse Reference

- Rich composable library—200+ utilities
- Study patterns in VueUse—excellent examples
- Don't reinvent—check if VueUse has it
- Extend VueUse composables rather than replacing


path: performance.md
content: # Performance Optimization

## Render Performance

- Vue tracks dependencies automatically—only re-renders what changes
- Keys on `v-for` are critical—use stable, unique ID, not array index
- `v-if` vs `v-show`: if unmounts, show toggles CSS—show better for frequent toggle
- `v-once` for static content—renders once, never updates

## Computed Optimization

- Computed values are cached—use for expensive derivations
- Computed only recalculates when dependencies change
- Avoid side effects in computed—can't rely on when they run
- Chain computed values—each caches independently

## Component Optimization

- Define components outside `<script setup>`—or use `defineComponent`
- Avoid inline handlers creating new functions: `:click="() => handle(item)"`
- For large lists, use virtual scrolling—vue-virtual-scroller
- Code split with `defineAsyncComponent`—load on demand

## Props Stability

- Object/array props create new reference each render
- Use `computed` or `toRef` for derived props—stable references
- `shallowRef` for large objects not deeply reactive
- `v-memo` for memoizing parts of template

## v-memo

- `v-memo="[dependency]"` caches template fragment
- Re-renders only when dependency changes
- Useful for large lists with selectable items
- More granular than component-level memoization

## List Optimization

- `key` must be stable and unique—not array index if list reorders
- `key` change triggers full component recreation—use for forced re-render
- Virtual scrolling for 1000+ items—don't render off-screen
- Paginate if possible—show 50, load more on demand

## Async Components

- `defineAsyncComponent` for lazy loading—reduces initial bundle
- Route-level code splitting—each route loads its components
- `<Suspense>` for coordinated async loading—show loading state
- Prefetch likely-needed components—on hover or visibility

## DevTools Profiling

- Vue DevTools has component inspector—see props, state
- Performance timeline shows render time
- Highlight updates option—visualize what re-renders
- Production build for accurate performance—dev mode adds overhead

## Build Optimization

- Tree-shaking removes unused code—don't import entire libraries
- `vue` runtime only build—smaller if not using template compiler
- `vite build` handles most optimizations automatically
- Analyze bundle: `vite-plugin-visualizer`—find heavy dependencies


path: reactivity.md
content: # Reactivity Patterns

## ref vs reactive Decision

- `ref` for primitives (string, number, boolean)—`.value` access
- `ref` also works for objects—sometimes clearer than reactive
- `reactive` for objects when you want direct property access
- Consistency wins: pick one style for your team

## ref Patterns

- Forgot `.value` in script—logs Ref object instead of value
- `.value` in template—unnecessary, auto-unwrapped
- `ref` with object value—still reactive, but `.value` for whole object
- `unref()` helper—returns value if ref, value itself if not

## reactive Patterns

- Reassigning whole object breaks reactivity—`state = newObj` doesn't work
- Destructuring loses reactivity—`const {count} = state` is not reactive
- `toRefs(state)` converts each property to ref—preserves reactivity
- `toRef(state, 'prop')` for single property to ref

## Shallow Reactivity

- `shallowRef` only tracks `.value` changes—nested changes not reactive
- `shallowReactive` only tracks root-level properties
- Use for performance with large objects—when deep reactivity not needed
- `triggerRef(ref)` manually triggers update for shallowRef

## readonly Protection

- `readonly(state)` creates read-only proxy—mutations silently fail
- Props are already readonly—no need to wrap
- Good for exposing state from composables—prevent external mutation
- `isReadonly()` to check if value is readonly

## Raw Values

- `toRaw(proxy)` gets original object from reactive proxy
- Useful for third-party libraries that don't handle Proxy
- Mutations on raw object won't trigger updates
- `markRaw(obj)` prevents object from ever becoming reactive

## Computed Patterns

- Computed with setter: `computed({ get, set })`—for two-way derived state
- Computed is cached—expensive calculations only run when dependencies change
- Avoid side effects in computed—use `watch` or `watchEffect` instead
- Computed ref unwraps in template—same as regular ref

## Effect Cleanup

- `watchEffect` receives cleanup function: `watchEffect((onCleanup) => {})`
- Clean up timers, subscriptions, event listeners
- Cleanup runs before effect re-runs AND on unmount
- Same pattern in `watch` callback—third argument


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)