
Plugin Vue 3 to obiekt z metodą install(app, options), instalowany przez app.use(). Rejestruje komponenty i dyrektywy, udostępnia wartości przez app.provide() i konfiguruje aplikację. Kod z Vue 2 oparty na Vue.prototype i Vue.mixin już nie działa.
Plugin Vue dodaje możliwości całej aplikacji naraz: komponent dostępny wszędzie, dyrektywę, wstrzykiwaną wartość, wspólną konfigurację. To ten sam mechanizm, który stoi za Vue Routerem, Pinią i większością bibliotek z ekosystemu.
Czym jest plugin
Obiektem z metodą install albo zwykłą funkcją. Vue wywołuje go z instancją aplikacji i opcjami przekazanymi do app.use().
export default {
install(app, options) {
// tu dzieje się wszystko
}
}W Vue 2 install dostawał globalny konstruktor Vue, a plugin grzebał w Vue.prototype, Vue.mixin czy Vue.component. W Vue 3 nie ma już globalnego konstruktora: install dostaje instancję utworzoną przez createApp i wszystko idzie przez nią. Plugin z Vue 2 przeniesiony bez zmian kończy się błędem Cannot set properties of undefined (setting '$api') albo cichą awarią.
Tabela odpowiedników:
// Vue 3
Vue.use(Plugin) app.use(Plugin)
Vue.component('X', X) app.component('X', X)
Vue.directive('x', x) app.directive('x', x)
Vue.mixin({ … }) app.mixin({ … })
Vue.prototype.$api = api app.config.globalProperties.$api = api
app.provide('api', api) // zalecaneKompletny plugin
Oto plugin, który zapisuje montowanie komponentów, udostępnia ten dziennik i dokłada dyrektywę. Pokazuje cztery punkty zaczepienia, które warto znać.
export default {
install(app, options = {}) {
const prefixe = options.prefixe ?? '[monitor]'
const journal = []
// 1. globalna właściwość, dostępna przez this w Options API
app.config.globalProperties.$journal = journal
// 2. wstrzykiwanie: zalecana droga przy <script setup>
app.provide('journal', journal)
// 3. globalna dyrektywa
app.directive('surligne', {
mounted(el, binding) {
el.style.backgroundColor = binding.value ?? '#fef08a'
}
})
// 4. globalny mixin, uruchamiany przy montowaniu każdego komponentu
app.mixin({
mounted() {
journal.push(`${prefixe} ${this.$options.__name ?? 'anonyme'} monté`)
}
})
}
}Instalacja, z opcjami albo bez:
import { createApp } from 'vue'
import App from './App.vue'
import monitor from './plugins/monitor.js'
const app = createApp(App)
app.use(monitor, { prefixe: '[gekkode]' })
app.mount('#app')Plugin zainstalowany dwa razy zostanie zastosowany tylko raz: Vue prowadzi rejestr pluginów, które już przeszły przez app.use().
provide zamiast globalProperties
app.config.globalProperties.$journal odtwarza nawyk z Vue 2, czyli this.$quelqueChose. Działa, ale w <script setup> nie ma this: właściwość jest osiągalna wyłącznie z szablonu albo z Options API. Wymyka się też autouzupełnianiu i typowaniu.
app.provide() to właściwa droga. Komponent odbiera wartość przez inject:
<script setup>
import { inject } from 'vue'
const journal = inject('journal')
</script>
<template>
<p>{{ journal.length }} composants montés</p>
</template>Żeby uniknąć kolizji nazw zapisanych jako zwykłe łańcuchy znaków, użyj Symbol eksportowanego przez plugin:
export const cleJournal = Symbol('journal')
export default {
install(app) {
app.provide(cleJournal, [])
}
}Rozdawanie komponentów
Najczęstszy przypadek: udostępnić bibliotekę komponentów bez importowania ich w każdym pliku.
import GkBouton from '../components/GkBouton.vue'
import GkCarte from '../components/GkCarte.vue'
export default {
install(app, { prefixe = 'Gk' } = {}) {
app.component(`${prefixe}Bouton`, GkBouton)
app.component(`${prefixe}Carte`, GkCarte)
}
}Uwaga na kompromis: komponent zarejestrowany globalnie jest dostępny wszędzie, ale wymyka się usuwaniu martwego kodu. Ląduje w bundlu, nawet jeśli nikt go nie używa. Rejestrację globalną zostaw dla komponentów naprawdę wszechobecnych.
Plugin może być zwykłą funkcją
Jeśli obiekt z metodą install wydaje ci się przesadnie uroczysty, wystarczy funkcja: Vue wywoła ją z tymi samymi argumentami.
export default function titrePlugin(app, options) {
app.config.globalProperties.$titre = options.titre
}Paczka gotowa do publikacji
Najpierw przetestuj plugin w świeżym projekcie Vite. Żeby wypuścić go na npm, wyeksportuj go domyślnie i zostaw zależność od Vue w peerDependencies, dzięki temu własną kopię dostarczy projekt, który plugin instaluje:
{
"name": "gekkode-monitor",
"type": "module",
"main": "./dist/index.js",
"exports": { ".": "./dist/index.js" },
"peerDependencies": { "vue": "^3.5.0" }
}Pluginy dla Vue 2 często kończyły się linijką if (window.Vue) window.Vue.use(Plugin), żeby instalować się same, gdy strona ładowała Vue znacznikiem script. W Vue 3 nie ma już globalnego window.Vue: ten blok do niczego nie służy i trzeba go usunąć.
Globalny mixin, w ostateczności
Przykładowy plugin sięga po app.mixin, żeby obserwować każde montowanie. To dobre narzędzie do potrzeb przekrojowych w rodzaju telemetrii, gdzie naprawdę chcesz dosięgnąć wszystkich komponentów.
Do wszystkiego innego wybierz composable: eksportowaną funkcję, którą wywołują zainteresowane komponenty. Globalny mixin działa wszędzie, także tam, gdzie nikt się go nie spodziewa, i utrudnia odnalezienie źródła danego zachowania.
import { inject } from 'vue'
export function useJournal() {
const journal = inject('journal')
return {
journal,
ajouter: (message) => journal.push(message)
}
}Testowanie pluginu
Vue Test Utils przyjmuje pluginy w opcji global, razem z ich opcjami:
import { mount } from '@vue/test-utils'
import monitor from '@/plugins/monitor.js'
mount(MonComposant, {
global: { plugins: [[monitor, { prefixe: '[test]' }]] }
})Bez opcji wystarczy krótka forma: plugins: [monitor].
Co dalej
Wiele bibliotek z ekosystemu instaluje się dokładnie w ten sposób, od VueFire po unhead odpowiadający za SEO.
Pluginy nabierają sensu dopiero wtedy, gdy masz opanowane komponenty i wstrzykiwanie zależności. Jeśli te pojęcia są jeszcze świeże, wróć do kursu Vue 3 dla początkujących, zwłaszcza do rozdziałów o komponentach i propsach. A jeśli szukasz współdzielonego stanu: Pinia sama jest pluginem i jej źródła to dobra lektura.
Częste błędy
install dostaje instancję aplikacji, a nie globalny konstruktor. Vue.prototype już nie istnieje: użyj app.provide() albo app.config.globalProperties.<script setup> nie ma this: właściwość odczytasz tylko z szablonu. Lepsze są provide i inject.if (window.Vue) window.Vue.use(Plugin) nie ma już czego szukać w Vue 3 i trzeba go usunąć.

