
Un plugin Vue 3 è un oggetto con un metodo install(app, options), installato con app.use(). Registra componenti e direttive, fornisce valori con app.provide() e configura l'applicazione. Il codice Vue 2 basato su Vue.prototype e Vue.mixin non funziona più.
Un plugin Vue aggiunge funzionalità a un’intera applicazione: un componente disponibile ovunque, una direttiva, un valore da iniettare, una configurazione comune. È il meccanismo dietro Vue Router, Pinia e gran parte delle librerie dell’ecosistema.
Che cos’è un plugin
Un oggetto con un metodo install, oppure una semplice funzione. Vue lo chiama passandogli l’istanza dell’applicazione e le opzioni date a app.use().
export default {
install(app, options) {
// qui succede tutto
}
}In Vue 2 install riceveva il costruttore globale Vue, e un plugin lavorava su Vue.prototype, Vue.mixin o Vue.component. In Vue 3 il costruttore globale non esiste più: install riceve l’istanza creata da createApp e tutto passa da lì. Un plugin Vue 2 ricopiato tale e quale fallisce con Cannot set properties of undefined (setting '$api') o si pianta in silenzio.
La tabella di corrispondenza:
// 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) // preferibileUn plugin completo
Ecco un plugin che registra il mount dei componenti, espone questo registro e fornisce una direttiva. Illustra i quattro punti di aggancio da conoscere.
export default {
install(app, options = {}) {
const prefixe = options.prefixe ?? '[monitor]'
const journal = []
// 1. proprietà globale, raggiungibile con this nella Options API
app.config.globalProperties.$journal = journal
// 2. inject: la via consigliata con <script setup>
app.provide('journal', journal)
// 3. direttiva globale
app.directive('surligne', {
mounted(el, binding) {
el.style.backgroundColor = binding.value ?? '#fef08a'
}
})
// 4. mixin globale, eseguito al mount di ogni componente
app.mixin({
mounted() {
journal.push(`${prefixe} ${this.$options.__name ?? 'anonyme'} monté`)
}
})
}
}Installazione, con o senza opzioni:
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')Un plugin installato due volte viene applicato una volta sola: Vue tiene traccia dei plugin già passati da app.use().
provide invece di globalProperties
app.config.globalProperties.$journal ricalca l’abitudine Vue 2 del this.$qualcosa. Funziona, ma this non esiste in <script setup>: la proprietà è raggiungibile solo dal template o dalla Options API. Ed è fuori dalla portata dell’autocompletamento e della tipizzazione.
app.provide() è la strada giusta. Il componente recupera il valore con inject:
<script setup>
import { inject } from 'vue'
const journal = inject('journal')
</script>
<template>
<p>{{ journal.length }} composants montés</p>
</template>Per evitare collisioni tra nomi in forma di stringa, usa un Symbol esportato dal plugin:
export const cleJournal = Symbol('journal')
export default {
install(app) {
app.provide(cleJournal, [])
}
}Distribuire componenti
Il caso più frequente: rendere una libreria di componenti disponibile senza 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)
}
}Attenzione al compromesso: un componente registrato globalmente è disponibile ovunque, ma sfugge al tree-shaking. Finisce nel bundle anche se non lo usa nessuno. Riserva la registrazione globale ai componenti davvero onnipresenti.
Un plugin può essere una semplice funzione
Se l’oggetto con il metodo install ti sembra troppo cerimonioso, basta una funzione: Vue la chiama con gli stessi argomenti.
export default function titrePlugin(app, options) {
app.config.globalProperties.$titre = options.titre
}Il pacchetto pubblicabile
Provalo prima in un progetto Vite nuovo. Per distribuirlo su npm esportalo come default e lascia la dipendenza da Vue nelle peerDependencies, così è il progetto ospite a fornire la propria copia:
{
"name": "gekkode-monitor",
"type": "module",
"main": "./dist/index.js",
"exports": { ".": "./dist/index.js" },
"peerDependencies": { "vue": "^3.5.0" }
}I plugin Vue 2 finivano spesso con if (window.Vue) window.Vue.use(Plugin), per installarsi da soli quando la pagina caricava Vue con un tag script. In Vue 3 non esiste più un window.Vue globale: quel blocco non serve a niente e va tolto.
Il mixin globale, come ultima risorsa
Il plugin di esempio usa app.mixin per osservare ogni mount. È lo strumento giusto per un’esigenza trasversale come la telemetria, dove vuoi davvero toccare tutti i componenti.
Per tutto il resto scegli un composable: una funzione esportata che chiamano i componenti interessati. Un mixin globale si applica ovunque, anche dove non te lo aspetti, e rende difficile risalire all’origine di un comportamento.
import { inject } from 'vue'
export function useJournal() {
const journal = inject('journal')
return {
journal,
ajouter: (message) => journal.push(message)
}
}Testare un plugin
Vue Test Utils accetta i plugin nell’opzione global, con le loro opzioni:
import { mount } from '@vue/test-utils'
import monitor from '@/plugins/monitor.js'
mount(MonComposant, {
global: { plugins: [[monitor, { prefixe: '[test]' }]] }
})Senza opzioni basta la forma breve: plugins: [monitor].
Per approfondire
Molte librerie dell’ecosistema si installano così, da VueFire a unhead per il posizionamento.
I plugin acquistano senso una volta padroneggiati i componenti e l’injection. Se questi concetti sono ancora freschi, riprendi il tutorial Vue 3 per principianti, in particolare i capitoli su componenti e props. Per uno stato condiviso, Pinia è a sua volta un plugin, e leggerne il sorgente è tempo ben speso.
Errori frequenti
install riceve l'istanza dell'applicazione, non più il costruttore globale. Vue.prototype non esiste più: usa app.provide() o app.config.globalProperties.this non esiste in <script setup>: la proprietà è leggibile solo dal template. Meglio provide e inject.if (window.Vue) window.Vue.use(Plugin) in Vue 3 non trova più nessun oggetto e va tolto.

