
Um plugin Vue 3 é um objeto com um método install(app, options), instalado com app.use(). Regista componentes e diretivas, fornece valores através de app.provide() e configura a aplicação. O código Vue 2 assente em Vue.prototype e Vue.mixin já não funciona.
Um plugin Vue acrescenta capacidades a uma aplicação inteira: um componente disponível em todo o lado, uma diretiva, um valor injetável, uma configuração comum. É o mecanismo por trás do Vue Router, do Pinia e da maior parte das bibliotecas do ecossistema.
O que é um plugin
Um objeto com um método install, ou simplesmente uma função. O Vue chama-o com a instância da aplicação e as opções passadas a app.use().
export default {
install(app, options) {
// é aqui que tudo acontece
}
}Em Vue 2, o install recebia o construtor global Vue, e um plugin mexia em Vue.prototype, Vue.mixin ou Vue.component. Em Vue 3 já não há construtor global: o install recebe a instância criada por createApp, e tudo passa por ela. Um plugin Vue 2 copiado tal e qual falha com Cannot set properties of undefined (setting '$api') ou estoira em silêncio.
A tabela de correspondência:
// 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) // preferívelUm plugin completo
Eis um plugin que regista a montagem dos componentes, expõe esse registo e fornece uma diretiva. Cobre os quatro pontos de ligação que interessa conhecer.
export default {
install(app, options = {}) {
const prefixe = options.prefixe ?? '[monitor]'
const journal = []
// 1. propriedade global, acessível por this na Options API
app.config.globalProperties.$journal = journal
// 2. injeção: a via recomendada com <script setup>
app.provide('journal', journal)
// 3. diretiva global
app.directive('surligne', {
mounted(el, binding) {
el.style.backgroundColor = binding.value ?? '#fef08a'
}
})
// 4. mixin global, executado na montagem de cada componente
app.mixin({
mounted() {
journal.push(`${prefixe} ${this.$options.__name ?? 'anonyme'} monté`)
}
})
}
}Instalação, com ou sem opções:
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')Um plugin instalado duas vezes só é aplicado uma: o Vue mantém o registo dos plugins que já passaram por app.use().
provide em vez de globalProperties
app.config.globalProperties.$journal reproduz o hábito do this.$qualquerCoisa do Vue 2. Funciona, mas o this não existe em <script setup>: a propriedade só é alcançável a partir do template ou da Options API. Também escapa ao autocompletar e à tipagem.
app.provide() é o caminho certo. O componente vai buscar o valor com inject:
<script setup>
import { inject } from 'vue'
const journal = inject('journal')
</script>
<template>
<p>{{ journal.length }} composants montés</p>
</template>Para evitar colisões de nomes em texto, usa um Symbol exportado pelo plugin:
export const cleJournal = Symbol('journal')
export default {
install(app) {
app.provide(cleJournal, [])
}
}Distribuir componentes
O caso mais comum: tornar uma biblioteca de componentes disponível sem 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)
}
}Atenção ao compromisso: um componente registado globalmente está disponível em todo o lado, mas escapa à eliminação de código morto. Acaba no bundle mesmo que ninguém o use. Reserva o registo global para os componentes verdadeiramente omnipresentes.
Um plugin pode ser uma simples função
Se o objeto com método install te parece cerimonioso, basta uma função: o Vue chama-a com os mesmos argumentos.
export default function titrePlugin(app, options) {
app.config.globalProperties.$titre = options.titre
}O pacote publicável
Testa-o primeiro num projeto Vite novo. Para o distribuir no npm, exporta-o por omissão e deixa a dependência do Vue em peerDependencies, para que o projeto anfitrião forneça a sua própria cópia:
{
"name": "gekkode-monitor",
"type": "module",
"main": "./dist/index.js",
"exports": { ".": "./dist/index.js" },
"peerDependencies": { "vue": "^3.5.0" }
}Os plugins Vue 2 terminavam muitas vezes com if (window.Vue) window.Vue.use(Plugin), para se instalarem sozinhos quando a página carregava o Vue por uma tag script. Em Vue 3 já não existe um window.Vue global: este bloco não serve para nada e deve ser retirado.
O mixin global, em último recurso
O plugin de exemplo usa app.mixin para observar cada montagem. É a ferramenta certa para uma necessidade transversal como a telemetria, em que queres mesmo tocar em todos os componentes.
Para tudo o resto, prefere um composable: uma função exportada que os componentes interessados chamam. Um mixin global aplica-se em todo o lado, incluindo onde não se espera, e torna difícil descobrir a origem de um comportamento.
import { inject } from 'vue'
export function useJournal() {
const journal = inject('journal')
return {
journal,
ajouter: (message) => journal.push(message)
}
}Testar um plugin
O Vue Test Utils aceita plugins na opção global, com as respetivas opções:
import { mount } from '@vue/test-utils'
import monitor from '@/plugins/monitor.js'
mount(MonComposant, {
global: { plugins: [[monitor, { prefixe: '[test]' }]] }
})Sem opções, basta a forma curta: plugins: [monitor].
Para ir mais longe
Muitas bibliotecas do ecossistema instalam-se assim, do VueFire ao unhead para o SEO.
Os plugins só ganham sentido depois de dominares os componentes e a injeção. Se estas noções ainda são recentes, volta ao tutorial de Vue 3 para principiantes, sobretudo aos capítulos sobre os componentes e as props. Para estado partilhado, o Pinia é ele próprio um plugin, e o seu código-fonte é uma boa leitura.
Erros frequentes
install recebe a instância da aplicação, já não o construtor global. Vue.prototype deixou de existir: usa app.provide() ou app.config.globalProperties.this não existe em <script setup>: a propriedade só se lê a partir do template. Prefere provide e inject.if (window.Vue) window.Vue.use(Plugin) já não encontra nada em Vue 3 e deve ser retirado.

