
Un plugin de Vue 3 es un objeto con un método install(app, options), que se instala con app.use(). Registra componentes y directivas, aporta valores mediante app.provide() y configura la aplicación. El código de Vue 2 basado en Vue.prototype y Vue.mixin ya no funciona.
Un plugin de Vue añade capacidades a toda una aplicación: un componente disponible en cualquier parte, una directiva, un valor inyectable, una configuración común. Es el mecanismo que hay detrás de Vue Router, Pinia y de casi todas las bibliotecas del ecosistema.
Qué es un plugin
Un objeto con un método install, o simplemente una función. Vue la llama con la instancia de la aplicación y las opciones pasadas a app.use().
export default {
install(app, options) {
// todo ocurre aquí
}
}En Vue 2, install recibía el constructor global Vue, y un plugin manipulaba Vue.prototype, Vue.mixin o Vue.component. En Vue 3 ya no hay constructor global: install recibe la instancia creada por createApp, y todo pasa por ella. Un plugin de Vue 2 copiado tal cual falla con Cannot set properties of undefined (setting '$api') o se cae en silencio.
La tabla de equivalencias:
// 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) // preferibleUn plugin completo
Este plugin registra el montaje de los componentes, expone ese registro y aporta una directiva. Muestra los cuatro puntos de enganche que hay que conocer.
export default {
install(app, options = {}) {
const prefixe = options.prefixe ?? '[monitor]'
const journal = []
// 1. propiedad global, accesible con this en la Options API
app.config.globalProperties.$journal = journal
// 2. inyección: la vía recomendada con <script setup>
app.provide('journal', journal)
// 3. directiva global
app.directive('surligne', {
mounted(el, binding) {
el.style.backgroundColor = binding.value ?? '#fef08a'
}
})
// 4. mixin global, ejecutado al montar cada componente
app.mixin({
mounted() {
journal.push(`${prefixe} ${this.$options.__name ?? 'anonyme'} monté`)
}
})
}
}Instalación, con o sin opciones:
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 instalado dos veces solo se aplica una: Vue lleva la cuenta de los plugins que ya han pasado por app.use().
provide antes que globalProperties
app.config.globalProperties.$journal reproduce la costumbre de Vue 2 del this.$loQueSea. Funciona, pero this no existe dentro de <script setup>: a esa propiedad solo se llega desde la plantilla o desde la Options API. Además se escapa del autocompletado y del tipado.
app.provide() es el camino correcto. El componente recupera el valor con inject:
<script setup>
import { inject } from 'vue'
const journal = inject('journal')
</script>
<template>
<p>{{ journal.length }} composants montés</p>
</template>Para evitar colisiones entre nombres en forma de cadena, usa un Symbol exportado por el plugin:
export const cleJournal = Symbol('journal')
export default {
install(app) {
app.provide(cleJournal, [])
}
}Distribuir componentes
El caso más habitual: poner una biblioteca de componentes a disposición de todos sin necesidad de importarla.
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)
}
}Cuidado con el peaje: un componente registrado globalmente está disponible en todas partes, pero queda fuera de la eliminación de código muerto. Acaba en el bundle aunque nadie lo use. Reserva el registro global para los componentes que de verdad estén en todas partes.
Un plugin puede ser una simple función
Si el objeto con método install te parece demasiada ceremonia, basta con una función: Vue la llama con los mismos argumentos.
export default function titrePlugin(app, options) {
app.config.globalProperties.$titre = options.titre
}El paquete publicable
Pruébalo antes en un proyecto Vite nuevo. Para distribuirlo en npm, expórtalo por defecto y deja la dependencia de Vue en peerDependencies, para que sea el proyecto anfitrión el que aporte su propia copia:
{
"name": "gekkode-monitor",
"type": "module",
"main": "./dist/index.js",
"exports": { ".": "./dist/index.js" },
"peerDependencies": { "vue": "^3.5.0" }
}Los plugins de Vue 2 solían terminar con if (window.Vue) window.Vue.use(Plugin), para instalarse solos cuando la página cargaba Vue con una etiqueta script. En Vue 3 ya no existe el window.Vue global: ese bloque no sirve de nada y hay que quitarlo.
El mixin global, como último recurso
El plugin de ejemplo usa app.mixin para observar cada montaje. Es la herramienta adecuada para una necesidad transversal como la telemetría, donde de verdad quieres tocar todos los componentes.
Para todo lo demás, tira de composable: una función exportada que llaman los componentes interesados. Un mixin global se aplica en todas partes, también donde no lo esperas, y dificulta localizar de dónde sale un comportamiento.
import { inject } from 'vue'
export function useJournal() {
const journal = inject('journal')
return {
journal,
ajouter: (message) => journal.push(message)
}
}Probar un plugin
Vue Test Utils acepta plugins en la opción global, con sus opciones:
import { mount } from '@vue/test-utils'
import monitor from '@/plugins/monitor.js'
mount(MonComposant, {
global: { plugins: [[monitor, { prefixe: '[test]' }]] }
})Sin opciones basta con la forma corta: plugins: [monitor].
Para ir más lejos
Muchas bibliotecas del ecosistema se instalan así, desde VueFire hasta unhead para el posicionamiento.
Los plugins cobran sentido cuando ya dominas los componentes y la inyección. Si esas nociones te quedan lejos, repasa el tutorial de Vue 3 para principiantes, sobre todo los capítulos dedicados a los componentes y las props. Para el estado compartido, Pinia es a su vez un plugin, y su código fuente es una buena lectura.
Errores frecuentes
install recibe la instancia de la aplicación, ya no el constructor global. Vue.prototype no existe: usa app.provide() o app.config.globalProperties.this no existe dentro de <script setup>: la propiedad solo se lee desde la plantilla. Es preferible provide e inject.if (window.Vue) window.Vue.use(Plugin) ya no encuentra nada en Vue 3 y hay que quitarlo.

