플러그인은 Vue 앱에 전역 수준의 기능을 추가하는 방법입니다. 앱 전체에서 사용하는 컴포넌트, 디렉티브, provide/inject를 한 번에 등록할 수 있습니다.

면접에서 "Vue 플러그인을 만들어본 적이 있나요?"라는 질문에, install 함수의 구조와 앱 인스턴스 API를 설명할 수 있으면 좋습니다.


플러그인 구조

TYPESCRIPT
// plugins/myPlugin.ts
import type { App, Plugin } from 'vue'

// 방법 1: install 메서드가 있는 객체
export const myPlugin: Plugin = {
  install(app: App, options?: { greeting?: string }) {
    // 1. 전역 컴포넌트 등록
    app.component('GlobalAlert', {
      template: '<div class="alert"><slot /></div>'
    })

    // 2. 전역 디렉티브 등록
    app.directive('highlight', {
      mounted(el: HTMLElement, binding) {
        el.style.backgroundColor = binding.value || 'yellow'
      }
    })

    // 3. provide — 모든 컴포넌트에서 inject 가능
    app.provide('greeting', options?.greeting || '안녕하세요')

    // 4. 전역 속성 추가 (Options API에서 this로 접근)
    app.config.globalProperties.$format = (date: Date) => {
      return date.toLocaleDateString('ko-KR')
    }
  }
}

// 방법 2: install 함수 자체를 플러그인으로
export function createLogger(): Plugin {
  return {
    install(app: App, options?: { level?: string }) {
      const logger = {
        log: (...args: any[]) => console.log('[LOG]', ...args),
        warn: (...args: any[]) => console.warn('[WARN]', ...args),
        error: (...args: any[]) => console.error('[ERROR]', ...args)
      }

      app.provide('logger', logger)
    }
  }
}
TYPESCRIPT
// main.ts
import { createApp } from 'vue'
import { myPlugin, createLogger } from './plugins/myPlugin'

const app = createApp(App)

app.use(myPlugin, { greeting: '환영합니다!' })
app.use(createLogger())

app.mount('#app')

실전 플러그인 — 국제화(i18n) 간이 버전

TYPESCRIPT
// plugins/i18n.ts
import type { App, Plugin, InjectionKey } from 'vue'

interface I18nMessages {
  [locale: string]: Record<string, string>
}

interface I18n {
  t: (key: string) => string
  locale: string
  setLocale: (locale: string) => void
}

export const I18nKey: InjectionKey<I18n> = Symbol('i18n')

export function createI18n(messages: I18nMessages): Plugin {
  return {
    install(app: App) {
      let currentLocale = 'ko'

      const i18n: I18n = {
        t(key: string) {
          return messages[currentLocale]?.[key] || key
        },
        get locale() {
          return currentLocale
        },
        setLocale(locale: string) {
          currentLocale = locale
        }
      }

      app.provide(I18nKey, i18n)

      // 전역 속성으로도 제공 (Options API 호환)
      app.config.globalProperties.$t = i18n.t
    }
  }
}
TYPESCRIPT
// main.ts
import { createI18n } from './plugins/i18n'

app.use(createI18n({
  ko: {
    'greeting': '안녕하세요',
    'button.submit': '제출',
    'button.cancel': '취소'
  },
  en: {
    'greeting': 'Hello',
    'button.submit': 'Submit',
    'button.cancel': 'Cancel'
  }
}))
VUE
<script setup lang="ts">
import { inject } from 'vue'
import { I18nKey } from '@/plugins/i18n'

const i18n = inject(I18nKey)!
</script>

<template>
  <p>{{ i18n.t('greeting') }}</p>
  <button>{{ i18n.t('button.submit') }}</button>
</template>

전역 속성의 TypeScript 타입 확장

TYPESCRIPT
// types/vue-global.d.ts
declare module 'vue' {
  interface ComponentCustomProperties {
    $format: (date: Date) => string
    $t: (key: string) => string
  }
}

export {}

플러그인 vs Composable

항목플러그인Composable
범위앱 전역컴포넌트 단위
등록app.use()import + 호출
용도전역 설정, 인프라특정 기능 로직
예시라우터, 상태 관리, i18nuseMouse, useFetch

면접 팁

  • Vue Router, Pinia 같은 공식 라이브러리도 플러그인 구조(app.use())를 따릅니다
  • 플러그인은 앱 초기화 시 한 번 실행되는 설정 이라는 점에서 Composable과 다릅니다
  • app.config.globalProperties는 Options API 호환용이며, Composition API에서는 provide/inject가 권장됩니다

요약

Vue 플러그인은 install 메서드를 통해 전역 컴포넌트, 디렉티브, provide/inject, 전역 속성을 한 번에 등록합니다. 앱 인프라 수준의 기능(i18n, 로깅, 분석)에 적합하며, 특정 기능 로직은 Composable을 사용하는 것이 더 적합합니다.

댓글 로딩 중...