
Een Vue 3-plugin is een object met een methode install(app, options), dat je installeert met app.use(). Hij registreert componenten en directives, levert waarden via app.provide() en configureert de applicatie. Vue 2-code op basis van Vue.prototype en Vue.mixin werkt niet meer.
Een Vue-plugin voegt functionaliteit toe aan een hele applicatie: een component dat overal beschikbaar is, een directive, een injecteerbare waarde, gedeelde configuratie. Het is het mechanisme achter Vue Router, Pinia en de meeste libraries uit het ecosysteem.
Wat een plugin is
Een object met een methode install, of gewoon een functie. Vue roept hem aan met de applicatie-instantie en de opties die je aan app.use() meegeeft.
export default {
install(app, options) {
// hier gebeurt alles
}
}In Vue 2 kreeg install de globale constructor Vue binnen, en sleutelde een plugin aan Vue.prototype, Vue.mixin of Vue.component. In Vue 3 bestaat die globale constructor niet meer: install krijgt de instantie die createApp heeft gemaakt, en alles loopt via die instantie. Een Vue 2-plugin die je klakkeloos overneemt, sneuvelt met Cannot set properties of undefined (setting '$api') of doet stilletjes niets.
De vertaaltabel:
// 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) // beterEen volledige plugin
Hieronder een plugin die het mounten van componenten logt, dat logboek beschikbaar stelt en een directive levert. Hij laat de vier aanhaakpunten zien die je moet kennen.
export default {
install(app, options = {}) {
const prefixe = options.prefixe ?? '[monitor]'
const journal = []
// 1. globale property, bereikbaar via this in de Options API
app.config.globalProperties.$journal = journal
// 2. injection: de aanbevolen weg met <script setup>
app.provide('journal', journal)
// 3. globale directive
app.directive('surligne', {
mounted(el, binding) {
el.style.backgroundColor = binding.value ?? '#fef08a'
}
})
// 4. globale mixin, draait bij het mounten van elk component
app.mixin({
mounted() {
journal.push(`${prefixe} ${this.$options.__name ?? 'anonyme'} monté`)
}
})
}
}Installeren, met of zonder opties:
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')Een plugin die twee keer geïnstalleerd wordt, wordt maar één keer toegepast: Vue houdt bij welke plugins al door app.use() zijn gegaan.
provide in plaats van globalProperties
app.config.globalProperties.$journal bootst de Vue 2-gewoonte van this.$ietsWat na. Dat werkt, maar this bestaat niet in <script setup>: de property is alleen bereikbaar vanuit het template of de Options API. Ze ontsnapt bovendien aan autocompletion en typing.
app.provide() is de juiste weg. Het component haalt de waarde op met inject:
<script setup>
import { inject } from 'vue'
const journal = inject('journal')
</script>
<template>
<p>{{ journal.length }} composants montés</p>
</template>Gebruik een Symbol dat de plugin exporteert om botsingen tussen stringnamen te voorkomen:
export const cleJournal = Symbol('journal')
export default {
install(app) {
app.provide(cleJournal, [])
}
}Componenten distribueren
Het meest voorkomende geval: een bibliotheek componenten beschikbaar maken zonder import.
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)
}
}Let op de afruil: een globaal geregistreerd component is overal beschikbaar, maar ontsnapt aan tree shaking. Het belandt in de bundle, ook als niemand het gebruikt. Houd globale registratie dus voor componenten die echt overal opduiken.
Een plugin mag ook gewoon een functie zijn
Vind je het object met een methode install te plechtig, dan volstaat een functie: Vue roept hem met dezelfde argumenten aan.
export default function titrePlugin(app, options) {
app.config.globalProperties.$titre = options.titre
}Het publiceerbare package
Test hem eerst in een vers Vite-project. Wil je hem op npm zetten, exporteer hem dan als default en houd de dependency op Vue in peerDependencies, zodat het gastproject zijn eigen kopie levert:
{
"name": "gekkode-monitor",
"type": "module",
"main": "./dist/index.js",
"exports": { ".": "./dist/index.js" },
"peerDependencies": { "vue": "^3.5.0" }
}Vue 2-plugins eindigden vaak met if (window.Vue) window.Vue.use(Plugin), om zichzelf te installeren wanneer de pagina Vue via een script-tag laadde. In Vue 3 bestaat er geen globale window.Vue meer: dat blok doet niets en hoort eruit.
De globale mixin, als laatste redmiddel
De voorbeeldplugin gebruikt app.mixin om elk mount-moment te observeren. Dat is het juiste gereedschap voor een dwarsdoorsnijdende behoefte als telemetrie, waarbij je echt alle componenten wilt raken.
Voor al het andere kies je een composable: een geëxporteerde functie die de betrokken componenten zelf aanroepen. Een globale mixin geldt overal, ook waar je hem niet verwacht, en maakt het lastig te achterhalen waar gedrag vandaan komt.
import { inject } from 'vue'
export function useJournal() {
const journal = inject('journal')
return {
journal,
ajouter: (message) => journal.push(message)
}
}Een plugin testen
Vue Test Utils accepteert plugins in de optie global, inclusief hun opties:
import { mount } from '@vue/test-utils'
import monitor from '@/plugins/monitor.js'
mount(MonComposant, {
global: { plugins: [[monitor, { prefixe: '[test]' }]] }
})Zonder opties volstaat de korte vorm: plugins: [monitor].
Verder lezen
Veel libraries uit het ecosysteem installeren zich op deze manier, van VueFire tot unhead voor de vindbaarheid.
Plugins komen pas tot hun recht zodra je componenten en injection onder de knie hebt. Zijn die begrippen nog vers, pak dan de Vue 3-tutorial voor beginners er weer bij, vooral de hoofdstukken over componenten en props. Voor gedeelde state is Pinia zelf een plugin, en de broncode ervan is goed leesvoer.
Veelgemaakte fouten
install krijgt de applicatie-instantie, niet langer de globale constructor. Vue.prototype bestaat niet meer: gebruik app.provide() of app.config.globalProperties.this bestaat niet in <script setup>: de property is alleen leesbaar vanuit het template. Kies liever provide en inject.if (window.Vue) window.Vue.use(Plugin) vindt in Vue 3 niets meer om aan te haken en hoort eruit.

