Comprehensive guide for Vue 3 application development using modern best practices (2025)...
To build modern Vue 3 applications, follow industry best practices based on the Composition API, <script setup> syntax, and the 2025 ecosystem (Vite, Vitest, TypeScript). This skill provides comprehensive guidance for Vue 3 development, from component creation to production optimization.
Current Vue Version: Vue 3.5.18 (as of 2025)
Build Tool: Vite (Vue CLI is legacy)
Testing: Vitest (Jest is legacy for Vue)
Standard: Composition API with <script setup> (Options API is legacy)
User Request → What are you building/fixing?
|
├─ Creating a new component?
│ └─ Use Quick Start: Creating Components (below)
│
├─ Need reusable logic?
│ ├─ Load references/composables-patterns.md
│ └─ Use asset: composable-template.ts
│
├─ State management question (ref vs reactive)?
│ └─ Load references/reactivity-guide.md
│
├─ Component communication (props/emits/slots)?
│ └─ Load references/component-patterns.md
│
├─ Performance issue or optimization?
│ └─ Load references/performance-optimization.md
│
├─ TypeScript setup or typing question?
│ └─ Load references/typescript-integration.md
│
├─ Writing tests?
│ └─ Load references/testing-guide.md
│
├─ Reviewing code or debugging?
│ └─ Load references/anti-patterns.md
│
└─ Learning Composition API basics?
└─ Load references/composition-api-guide.md
<script setup><script setup>
import { ref, computed } from 'vue'
const count = ref(0)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ double }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<style scoped>
/* Component styles */
</style>
<script setup lang="ts">
// Props
const props = defineProps<{
title: string
count?: number
}>()
// Emits
const emit = defineEmits<{
update: [value: number]
close: []
}>()
// Local state
const localCount = ref(props.count ?? 0)
// Methods
function handleUpdate() {
emit('update', localCount.value)
}
</script>
<template>
<div>
<h2>{{ title }}</h2>
<button @click="handleUpdate">Update</button>
</div>
</template>
For a complete component template, use component-template.vue.
Composables are reusable functions that encapsulate stateful logic.
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
function decrement() {
count.value--
}
return {
count,
double,
increment,
decrement
}
}
Usage in component:
<script setup>
import { useCounter } from '@/composables/useCounter'
const { count, double, increment } = useCounter(5)
</script>
For a complete composable template, use composable-template.ts.
.vue extension<script setup lang="ts"> at topdefineProps<T>()defineEmits<T>()ref() or reactive()onMounted, onUnmounted, etc.)composables/ directory with use*.ts namingref() or reactive()onUnmounted if neededv-show vs v-if appropriatelyv-for lists*.spec.ts file next to component@vue/test-utils or @testing-library/vuenpm run test<script setup lang="ts">
import { reactive, computed } from 'vue'
interface FormData {
email: string
password: string
}
const form = reactive<FormData>({
email: '',
password: ''
})
const errors = reactive({
email: '',
password: ''
})
const isValid = computed(() => {
return form.email.includes('@') && form.password.length >= 8
})
function validate() {
errors.email = form.email.includes('@') ? '' : 'Invalid email'
errors.password = form.password.length >= 8 ? '' : 'Password too short'
}
async function handleSubmit() {
validate()
if (!isValid.value) return
// Submit form
await api.submit(form)
}
</script>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const data = ref(null)
const loading = ref(false)
const error = ref(null)
async function fetchData() {
loading.value = true
error.value = null
try {
const response = await fetch('/api/data')
data.value = await response.json()
} catch (e) {
error.value = e.message
} finally {
loading.value = false
}
}
onMounted(() => {
fetchData()
})
</script>
<template>
<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error }}</div>
<div v-else>{{ data }}</div>
</template>
<script setup lang="ts">
const props = defineProps<{
modelValue: boolean
title: string
}>()
const emit = defineEmits<{
'update:modelValue': [value: boolean]
confirm: []
}>()
function close() {
emit('update:modelValue', false)
}
function confirm() {
emit('confirm')
close()
}
</script>
<template>
<Teleport to="body">
<div v-if="modelValue" class="modal-overlay" @click="close">
<div class="modal-content" @click.stop>
<h2>{{ title }}</h2>
<slot />
<div class="modal-actions">
<button @click="close">Cancel</button>
<button @click="confirm">Confirm</button>
</div>
</div>
</div>
</Teleport>
</template>
Use virtual scrolling for large lists (1000+ items):
<script setup>
// Use a virtual scrolling library like vue-virtual-scroller
import { RecycleScroller } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
const items = ref(Array.from({ length: 10000 }, (_, i) => ({
id: i,
name: `Item ${i}`
})))
</script>
<template>
<RecycleScroller
:items="items"
:item-size="50"
key-field="id"
v-slot="{ item }"
>
<div class="item">{{ item.name }}</div>
</RecycleScroller>
</template>
<script setup> for all new components - It's the 2025 standardref() over reactive() - More consistent and flexibleonUnmounted - Prevent memory leaksuse* for composables, PascalCase for componentsv-if/v-show - Wrong choice = 3x slowerv-for - Causes rendering bugsThis skill includes comprehensive reference guides and ready-to-use templates:
Complete guide to Vue 3 Composition API and <script setup> syntax. Covers defineProps, defineEmits, lifecycle hooks, template refs, and combining with normal <script>.
Load when: Learning Composition API, understanding <script setup>, working with props/emits, using lifecycle hooks.
Deep dive into Vue 3's reactivity system. Covers ref() vs reactive(), toRefs(), computed properties, watch() vs watchEffect(), and common reactivity pitfalls.
Load when: Choosing between ref and reactive, managing state, creating computed values, watching for changes, debugging reactivity issues.
Comprehensive guide to creating reusable composables. Covers naming conventions, structure patterns, common use cases (API fetching, event listeners), VueUse examples, and testing composables.
Load when: Creating composables, extracting reusable logic, learning from VueUse patterns, testing composables.
Guide to Vue 3 component design patterns. Covers props (TypeScript + validation), emits (typed events), slots (default, named, scoped), provide/inject, and component composition strategies.
Load when: Designing component APIs, working with props/emits/slots, using provide/inject, composing components.
Performance optimization techniques for Vue 3. Covers lazy loading, code splitting, v-show vs v-if, virtual scrolling, computed caching, bundle optimization, and Vue 3.5 performance improvements (56% memory reduction).
Load when: Optimizing performance, reducing bundle size, implementing lazy loading, debugging slow renders, analyzing builds.
Complete TypeScript integration guide. Covers project setup with Vite, typing props/emits/refs, generic components, Volar extension setup, and migration from JavaScript.
Load when: Setting up TypeScript, typing components, using Volar, migrating from JavaScript, resolving type errors.
Testing strategies with Vitest and Testing Library. Covers Vitest setup, component testing, testing props/emits/slots, testing composables, mocking, async testing, and E2E considerations.
Load when: Writing tests, setting up Vitest, testing components/composables, mocking dependencies, debugging tests.
Common Vue 3 mistakes and anti-patterns to avoid. Covers 14 anti-patterns including Options API usage, v-if/v-show misuse, prop drilling, reactivity pitfalls, memory leaks, and bundle size issues.
Load when: Reviewing code, debugging issues, learning what to avoid, code review feedback, performance problems.
Production-ready Vue 3 component template with TypeScript, props, emits, reactive state, computed values, methods, and lifecycle hooks. Includes scoped styles and comprehensive examples.
Use when: Creating new components, need a starting template, teaching component structure.
Production-ready composable template with TypeScript, options object, reactive state, computed values, cleanup, and full JSDoc documentation. Includes useCounter example.
Use when: Creating new composables, need a starting template, learning composable structure.
Complete Vite configuration for Vue 3 projects. Includes Vue plugin setup, path aliases, dev server config, build optimization, chunk splitting, and CSS preprocessing.
Use when: Setting up new project, configuring Vite, optimizing build, adding aliases.
<script setup> - Cleaner syntax, better performance, less boilerplateThis skill is based on:
The Vue ecosystem has matured significantly in 2025. The Composition API with <script setup> is now the standard approach for all new Vue development.