更新日:2025/10/23
Best Practices in Vue 3
Vue.js 3 is one of the most elegant and efficient JavaScript frameworks for building modern web applications. Its Composition API, reactivity system, and flexibility make it a top choice among developers worldwide. However, like any powerful tool, achieving high-quality, maintainable, and performant applications requires understanding and following best practices. This guide explores the most effective strategies and techniques for developing with Vue 3, including examples and explanations to help you write professional, scalable code.

A well-organized project structure improves scalability, readability, and team collaboration. Vue 3 allows flexible setups, but consistency is key. Always follow a clear convention for your directories.
Use a modular and feature-based structure rather than grouping only by file type.
src/
├─ api/ // API request functions
├─ assets/ // Images, fonts, and static files
├─ components/ // Reusable UI components
├─ composables/ // Reusable logic using Composition API
├─ layouts/ // Layout components
├─ pages/ // View-level components (for routing)
├─ store/ // Pinia stores
├─ router/ // Vue Router setup
├─ utils/ // Utility functions
└─ App.vue
The Composition API in Vue 3 provides a flexible and scalable way to manage logic. It promotes better code organization and reusability. However, misusing it can lead to unreadable code.
Whenever you find logic that could be reused across multiple components, extract it into a composable. This promotes DRY (Don’t Repeat Yourself) principles.
// composables/useFetch.js
import { ref } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const loading = ref(false)
const fetchData = async () => {
loading.value = true
try {
const res = await fetch(url)
data.value = await res.json()
} catch (err) {
error.value = err
} finally {
loading.value = false
}
}
return { data, error, loading, fetchData }
}
Each composable should handle a single, well-defined purpose. Avoid making “god” composables that handle multiple unrelated tasks.
Overuse of watchers can complicate reactivity and cause performance issues. Prefer computed properties when possible, as they are cached and declarative.
// ❌ Bad: Using watch for derived state
watch(() => count.value, (newCount) => {
double.value = newCount * 2
})
// ✅ Good: Use computed instead
const double = computed(() => count.value * 2)
Components are the backbone of Vue applications. Proper component design ensures reusability, readability, and performance.
Each component should ideally do one thing well. If a component grows too large, split it into smaller subcomponents.
Props and emits define the public API of your component. Be explicit about what props your component accepts and what events it emits.
<script setup>
import { defineProps, defineEmits } from 'vue'
const props = defineProps({
label: String,
modelValue: String
})
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<label>{{ label }}</label>
<input
:value="modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
If you find yourself passing props through multiple layers of components, consider using the Context API or a store (e.g., Pinia) to share state efficiently.
Slots allow components to remain flexible while providing structure.
<template>
<div class="card">
<header>
<slot name="header">Default Header</slot>
</header>
<main>
<slot></slot>
</main>
</div>
</template>
Vue 3 officially recommends Pinia for state management. It’s type-safe, modular, and more intuitive than Vuex.
Create one store per domain (e.g., user, product, settings) rather than one large store.
// stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
name: '',
isLoggedIn: false
}),
actions: {
login(username) {
this.name = username
this.isLoggedIn = true
},
logout() {
this.name = ''
this.isLoggedIn = false
}
}
})
For user sessions or preferences, persist state using localStorage or plugins.
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
userStore.$subscribe((mutation, state) => {
localStorage.setItem('user', JSON.stringify(state))
})
Do not store data that can be computed from existing state. Use computed properties or getters instead.
Performance issues can easily appear in large applications. Vue 3 offers many ways to optimize rendering and reactivity.
If an element or component does not change, use v-once to render it once.
<h1 v-once>Static Title</h1>
Reactivity can be expensive if used carelessly. Avoid making entire objects reactive when you only need a single value.
// ❌ Avoid this
const state = reactive({ count: 0 })
// ✅ Better
const count = ref(0)
Lazy load components to improve initial load time.
const routes = [
{
path: '/about',
component: () => import('@/pages/About.vue')
}
]
Always use a unique key for list rendering to help Vue efficiently track changes.
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
Clean templates and organized styles make your Vue components easy to read and maintain.
Use <style scoped> to prevent CSS conflicts between components.
<style scoped>
.button {
background-color: #42b983;
}
</style>
For larger projects, use CSS modules or utility frameworks like Tailwind CSS for better maintainability.
Avoid putting complex logic inside templates. Use computed properties and methods instead.
// ❌ Bad
<div>{{ user.age >= 18 ? 'Adult' : 'Minor' }}</div>
// ✅ Good
<div>{{ userStatus }}</div>
<script setup>
const userStatus = computed(() => user.age >= 18 ? 'Adult' : 'Minor')
</script>
Testing ensures that your Vue components work as expected and remain stable during updates.
Vue Test Utils is the official unit testing library for Vue components. Combine it with Jest for comprehensive testing.
// Example: Button.spec.js
import { mount } from '@vue/test-utils'
import Button from '@/components/Button.vue'
test('renders label correctly', () => {
const wrapper = mount(Button, {
props: { label: 'Click Me' }
})
expect(wrapper.text()).toContain('Click Me')
})
Install Vue DevTools to inspect component trees, props, events, and performance in real-time.
Avoid leaving console logs in production. Use proper error handling or logging tools like Sentry.
Graceful error handling is critical for a robust user experience.
try {
await api.getUser()
} catch (error) {
console.error('Failed to fetch user', error)
}
You can use the errorCaptured lifecycle hook or global handlers for unhandled errors.
onErrorCaptured((err, instance, info) => {
console.error('Error:', err, info)
return false
})
Use libraries like yup or vee-validate for consistent form validation.
Maintainability ensures your project remains easy to evolve over time.
Linting enforces consistency across your codebase. Use eslint-plugin-vue for Vue-specific rules.
Follow the official Vue Style Guide for naming conventions, template structure, and recommended practices.
Document component props, events, and usage examples to help your team and future maintainers.
After development, optimizing for production is crucial for performance and reliability.
Keep API keys and environment-specific configurations outside of your source code.
VITE_API_URL=https://api.example.com
Vite and Vue automatically support code splitting, but be sure to lazy-load large dependencies.
Use modern image formats (WebP, AVIF) and lazy loading for images to reduce bandwidth.
Use tools like Lighthouse or Sentry Performance to track load times and errors in production.
Building scalable, maintainable, and performant Vue 3 applications requires more than just syntax knowledge. It involves adhering to consistent architecture, following composition patterns, optimizing rendering, and writing clean, testable code. By following the best practices outlined above — from composables and component structure to state management and deployment — you ensure your Vue 3 projects remain stable, readable, and efficient. Vue’s ecosystem is constantly evolving, so keep learning and refining your practices to stay ahead in modern web development.
Best Practices in Vue 3
オフショア開発のご紹介資料