🚀 Vue 3에서 자주 사용하는 핵심 기능들 — 플러그인, 컴포저블, provide/inject, 커스텀 디렉티브 — 각각의 역할과 차이점을 한 눈에 정리해봅니다.
기능 | 한 줄 요약 설명 | 언제 써야 할까? |
---|---|---|
📦 플러그인 | 앱 전체에서 공통 기능을 설정할 때 사용 | $api , $log 등 전역 기능이 필요할 때 |
🧩 컴포저블 | 컴포넌트 내부 로직을 재사용할 때 적합 | 여러 컴포넌트에서 동일한 상태 관리나 로직이 반복될 때 |
🔗 provide / inject | 조상 컴포넌트에서 자식 컴포넌트로 데이터 전달 | 설정값이나 공통 데이터를 자식 컴포넌트에 내려줄 때 |
🎯 커스텀 디렉티브 | 엘리먼트에 직접 동작을 붙일 때 사용 | 포커스 자동 부여, 외부 클릭 감지 등 DOM 조작이 필요할 때 |
항목 | 📦 플러그인 | 🧩 컴포저블 | 🔗 provide / inject | 🎯 커스텀 디렉티브 |
---|---|---|---|---|
주요 목적 | 앱 전체 설정, 전역 기능 추가 | 재사용 가능한 로직 분리 | 조상 → 자식 간 데이터 전달 | DOM 직접 제어 |
사용 위치 | main.js → app.use() | 컴포넌트 내부 setup() | setup() 내 provide , inject | 엘리먼트에 디렉티브로 사용 (v-* ) |
전역 설정 가능 | ✅ (app.config , app.component 등) | ❌ | ❌ | ❌ |
전역 속성 추가 | ✅ ($log , $api 등) | ❌ | ❌ | ❌ |
재사용 가능 | ✅ (라이브러리처럼 배포 가능) | ✅ (로직 중심 재사용) | ✅ (여러 컴포넌트에서 공유 가능) | ✅ (디렉티브 재등록 가능) |
DOM 직접 접근 | ❌ | 제한적 (ref 등으로 가능) | ❌ | ✅ (focus , scroll 등) |
예시 | Vue Router , i18n , Toast | useAuth() , useDarkMode() | 테마 설정, 글로벌 서비스 공유 | v-focus , v-scroll 등 |
Vue 내장 기능 의존 | 많이 사용 (app.* ) | Composition API만 사용 | Composition API만 사용 | Directive API 사용 |
// myPlugin.js
export default {
install(app, options) {
app.config.globalProperties.$sayHello = () => console.log('Hello!');
app.provide('pluginData', options?.message || 'Default Message');
}
}
// main.js
import myPlugin from './myPlugin';
app.use(myPlugin, { message: 'Hello from plugin!' });
// useCounter.js
import { ref } from 'vue';
export function useCounter() {
const count = ref(0);
const increment = () => count.value++;
return { count, increment };
}
// 컴포넌트 내부
const { count, increment } = useCounter();
<!-- ParentComponent.vue -->
<script setup>
import { provide } from 'vue';
provide('message', 'Hello from parent!');
</script>
<!-- ChildComponent.vue -->
<script setup>
import { inject } from 'vue';
const message = inject('message');
</script>
<template>
<div>{{ message }}</div>
</template>
// directives/v-focus.js
export default {
mounted(el) {
el.focus();
}
}
// main.js
import vFocus from './directives/v-focus';
app.directive('focus', vFocus);
// inputComponent.vue
<!-- 사용 -->
<input v-focus />
Vue 플러그인은 전역 기능을 설정하거나 앱 전체에서 반복되는 로직을 쉽게 공유할 수 있어요.
아래는 실무에서 provide/inject 방식으로 많이 사용하는 전형적인 예시입니다:
사용 예 | 설명 |
---|---|
✅ $api | HTTP 요청 관련 함수들을 묶어서 전역에서 사용 (getUser() , getPosts() 등) |
✅ $auth | 로그인 상태, 사용자 정보, 토큰 처리 등 인증 관련 로직 공유 |
✅ $logger | 개발 중 콘솔 로그 또는 에러 로깅 기능 전역 제공 |
✅ $toast | 알림/토스트 메시지 전역 호출 ($toast.success('완료!') ) |
$api
플러그인// plugins/api.js
export default {
install(app, options) {
const api = {
getUser() {
return fetch(`${options.baseUrl}/user`).then(res => res.json())
},
getPosts() {
return fetch(`${options.baseUrl}/posts`).then(res => res.json())
}
}
app.provide('$api', api)
}
}
$auth
플러그인// plugins/auth.js
export default {
install(app) {
const auth = {
isLoggedIn: () => !!localStorage.getItem('token'),
getToken: () => localStorage.getItem('token'),
login(token) {
localStorage.setItem('token', token)
},
logout() {
localStorage.removeItem('token')
}
}
app.provide('$auth', auth)
}
}
$logger
플러그인// plugins/logger.js
export default {
install(app) {
const logger = {
log: (...args) => console.log('[LOG]', ...args),
warn: (...args) => console.warn('[WARN]', ...args),
error: (...args) => console.error('[ERROR]', ...args)
}
app.provide('$logger', logger)
}
}
$toast
플러그인 (예: 간단한 alert 기반)// plugins/toast.js
export default {
install(app) {
const toast = {
success: (msg) => alert(`✅ Success: ${msg}`),
error: (msg) => alert(`❌ Error: ${msg}`)
}
app.provide('$toast', toast)
}
}
import { createApp } from 'vue'
import App from './App.vue'
import apiPlugin from './plugins/api'
import authPlugin from './plugins/auth'
import loggerPlugin from './plugins/logger'
import toastPlugin from './plugins/toast'
const app = createApp(App)
app.use(apiPlugin, { baseUrl: 'https://jsonplaceholder.typicode.com' })
app.use(authPlugin)
app.use(loggerPlugin)
app.use(toastPlugin)
app.mount('#app')
<script setup>
import { inject } from 'vue'
const $api = inject('$api')
const $auth = inject('$auth')
const $logger = inject('$logger')
const $toast = inject('$toast')
// 예시 사용
onMounted(async () => {
if ($auth.isLoggedIn()) {
const user = await $api.getUser()
$logger.log('User loaded:', user)
$toast.success('사용자 정보를 불러왔습니다!')
} else {
$toast.error('로그인이 필요합니다.')
}
})
</script>
💡
app.provide()
를 활용한 플러그인은 Composition API와 궁합이 좋고,
inject()
로 필요한 곳에서만 선택적으로 사용할 수 있어 유지보수가 편해요.