Vue
Anthony FuCommunityCreated by Anthony Fu
- Skill
- Tool integration
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured reference for building modern Vue 3 applications. It emphasizes the use of the Composition API and script setup syntax, offering guidance on reactivity primitives, lifecycle hooks, and built-in components. It covers essential patterns for managing component state, side effects, and DOM interactions, ensuring developers follow current best practices for performance and maintainability.
What it does
- Provides syntax patterns for script setup macros like defineProps, defineEmits, and defineModel.
- Explains the reactivity system including ref, shallowRef, computed, and watch.
- Details the usage of built-in components such as Transition, Teleport, Suspense, and KeepAlive.
- Outlines lifecycle hooks and their appropriate use cases within components.
- Offers guidance on effect scopes and composable patterns for managing reactive state.
- Includes quick reference templates for standard component structures.
When to use it
- When developing Vue 3 single-file components using the Composition API.
- When implementing complex reactivity or state management within a component.
- When handling component animations, portal rendering, or async loading states.
- When optimizing component performance using shallow reactivity or specific lifecycle management.
- When standardizing code structure across a Vue project.
Advantages
- Promotes consistent use of the modern Composition API and TypeScript.
- Provides clear performance optimization strategies like shallowRef.
- Simplifies complex tasks like DOM teleportation and async component handling.
- Encourages clean code through standardized script setup macros.
- Offers a centralized reference for Vue 3.5+ features.
Usage examples
- “How do I define props and emits in a Vue 3 script setup component?”
- The agent provides a code snippet using defineProps and defineEmits within a script setup block, demonstrating type-safe property and event definitions.
- “Show me how to use Teleport to render a modal in the body.”
- The agent generates a template example using the Teleport component with the to=body attribute to move content to the document root.
- “What is the difference between ref and shallowRef?”
- The agent explains that ref provides deep reactivity while shallowRef only tracks changes to the .value assignment, recommending shallowRef for performance optimization.
- “How can I watch a prop for changes in Vue 3?”
- The agent provides a watch function example that monitors a getter for the specific prop, including configuration options like immediate execution.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/antfu/vue/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip vue.zip -d .agents/skills
Documentation by Anthony Fu
Vue
Based on Vue 3.5, generated at 2026-09-25. Always use Composition API with
<script setup lang="ts">.
Preferences
Prefer TypeScript over JavaScript
Prefer
<script setup lang="ts">over<script>For performance, prefer
shallowRefoverrefif deep reactivity is not neededAlways use Composition API over Options API
Discourage using Reactive Props Destructure
Core
| Topic | Description | Reference |
|---|---|---|
| Script Setup & Macros | <script setup>, defineProps, defineEmits, defineModel, defineExpose, defineOptions, defineSlots, generics | script-setup-macros |
| Reactivity & Lifecycle | ref, shallowRef, computed, watch, watchEffect, effectScope, lifecycle hooks, composables | core-new-apis |
Features
| Topic | Description | Reference |
|---|---|---|
| Built-in Components & Directives | Transition, Teleport, Suspense, KeepAlive, v-memo, custom directives | advanced-patterns |
Quick Reference
Component Template
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
const props = defineProps<{
title: string
count?: number
}>()
const emit = defineEmits<{
update: [value: string]
}>()
const model = defineModel<string>()
const doubled = computed(() => (props.count ?? 0) * 2)
watch(() => props.title, (newVal) => {
console.log('Title changed:', newVal)
})
onMounted(() => {
console.log('Component mounted')
})
</script>
<template>
<div>{{ title }} - {{ doubled }}</div>
</template>Key Imports
// Reactivity
import { ref, shallowRef, computed, reactive, readonly, toRef, toRefs, toValue } from 'vue'
// Watchers
import { watch, watchEffect, watchPostEffect, onWatcherCleanup } from 'vue'
// Lifecycle
import { onMounted, onUpdated, onUnmounted, onBeforeMount, onBeforeUpdate, onBeforeUnmount } from 'vue'
// Utilities
import { nextTick, defineComponent, defineAsyncComponent } from 'vue'Files
- ATTRIBUTION.mdAdded by AutoGineer886 B
- GENERATION.md133 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md2.4 KiB
- references/advanced-patterns.md6.1 KiB
- references/core-new-apis.md5.6 KiB
- references/script-setup-macros.md4.0 KiB
references/core-new-apis.md
name: core-new-apis description: Vue 3 reactivity system, lifecycle hooks, and composable patterns
Reactivity, Lifecycle & Composables
Reactivity
ref vs shallowRef
import { ref, shallowRef } from 'vue'
// ref - deep reactivity (tracks nested changes)
const user = ref({ name: 'John', profile: { age: 30 } })
user.value.profile.age = 31 // Triggers reactivity
// shallowRef - only .value assignment triggers reactivity (better performance)
const data = shallowRef({ items: [] })
data.value.items.push('new') // Does NOT trigger reactivity
data.value = { items: ['new'] } // Triggers reactivityPrefer shallowRef for large data structures or when deep reactivity is unnecessary.
computed
import { ref, computed } from 'vue'
const count = ref(0)
// Read-only computed
const doubled = computed(() => count.value * 2)
// Writable computed
const plusOne = computed({
get: () => count.value + 1,
set: (val) => { count.value = val - 1 }
})reactive & readonly
import { reactive, readonly } from 'vue'
const state = reactive({ count: 0, nested: { value: 1 } })
state.count++ // Reactive
const readonlyState = readonly(state)
readonlyState.count++ // Warning, mutation blockedNote: reactive() loses reactivity on destructuring. Use ref() or toRefs().
Inspecting reactive values
import { isRef, isReactive, isReadonly, isProxy, isShallow, unref, toRaw } from 'vue'
isShallow(shallowRef(0)) // true, also true for shallowReactive/shallowReadonly
isShallow(ref(0)) // falseisShallow() reports whether a proxy was created with shallowRef, shallowReactive(), or shallowReadonly().
Watchers
watch
import { ref, watch } from 'vue'
const count = ref(0)
// Watch single ref
watch(count, (newVal, oldVal) => {
console.log(`Changed from ${oldVal} to ${newVal}`)
})
// Watch getter
watch(
() => props.id,
(id) => fetchData(id),
{ immediate: true }
)
// Watch multiple sources
watch([firstName, lastName], ([first, last]) => {
fullName.value = `${first} ${last}`
})
// Deep watch with depth limit (Vue 3.5+)
watch(state, callback, { deep: 2 })
// Once (Vue 3.4+)
watch(source, callback, { once: true })watchEffect
Runs immediately and auto-tracks dependencies.
import { ref, watchEffect, onWatcherCleanup } from 'vue'
const id = ref(1)
watchEffect(async () => {
const controller = new AbortController()
// Cleanup on re-run or unmount (Vue 3.5+)
onWatcherCleanup(() => controller.abort())
const res = await fetch(`/api/${id.value}`, { signal: controller.signal })
data.value = await res.json()
})
// Pause/resume (Vue 3.5+)
const { pause, resume, stop } = watchEffect(() => {})
pause()
resume()
stop()Flush Timing
// 'pre' (default) - before component update
// 'post' - after component update (access updated DOM)
// 'sync' - immediate, use with caution
watch(source, callback, { flush: 'post' })
watchPostEffect(() => {}) // Alias for flush: 'post'Lifecycle Hooks
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onErrorCaptured,
onActivated, // KeepAlive
onDeactivated, // KeepAlive
onServerPrefetch // SSR only
} from 'vue'
onMounted(() => {
console.log('DOM is ready')
})
onUnmounted(() => {
// Cleanup timers, listeners, etc.
})
// Error boundary
onErrorCaptured((err, instance, info) => {
console.error(err)
return false // Stop propagation
})Effect Scope
Group reactive effects for batch disposal.
import { effectScope, onScopeDispose } from 'vue'
const scope = effectScope()
scope.run(() => {
const count = ref(0)
const doubled = computed(() => count.value * 2)
watch(count, () => console.log(count.value))
// Cleanup when scope stops
onScopeDispose(() => {
console.log('Scope disposed')
})
})
// Dispose all effects
scope.stop()Composables
Composables are functions that encapsulate stateful logic using Composition API.
Naming Convention
Start with
use:useMouse,useFetch,useCounter
Pattern
// composables/useMouse.ts
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
const update = (e: MouseEvent) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
}Accept Reactive Input
Use toValue() (Vue 3.3+) to normalize refs, getters, or plain values.
import { ref, watchEffect, toValue, type MaybeRefOrGetter } from 'vue'
export function useFetch(url: MaybeRefOrGetter<string>) {
const data = ref(null)
const error = ref(null)
watchEffect(async () => {
data.value = null
error.value = null
try {
const res = await fetch(toValue(url))
data.value = await res.json()
} catch (e) {
error.value = e
}
})
return { data, error }
}
// Usage - all work:
useFetch('/api/users')
useFetch(urlRef)
useFetch(() => `/api/users/${props.id}`)Return Refs (Not Reactive)
Always return plain object with refs for destructuring compatibility.
// Good - preserves reactivity when destructured
return { x, y }
// Bad - loses reactivity when destructured
return reactive({ x, y })<!-- Source references: - https://vuejs.org/api/reactivity-core.html - https://vuejs.org/api/reactivity-advanced.html - https://vuejs.org/api/composition-api-lifecycle.html - https://vuejs.org/guide/reusability/composables.html -->
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Anthony Fu
- Publisher
- Anthony Fu (Community)
- Source
- antfu/skills · skills/vue · commit f63e9ec
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Anthony Fu or Anthony Fu.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download vue.zip