Todo mundo familiarizado com o Vue sabe que um aplicativo Vue tem um ponto de entrada - o arquivo
main.js
Lá, além de criar uma instância do Vue, há uma importação e um tipo de Injeção de Dependências de todas as suas dependências globais (diretivas, componentes, plugins). Quanto maior o projeto, mais dependências se tornam, e cada uma delas tem sua própria configuração. Como resultado, obtemos um arquivo enorme com todas as configurações.
Este artigo discutirá como organizar dependências globais para evitar isso.

Por que escrever você mesmo?
Muitos podem pensar - por que isso é necessário se existe, por exemplo, o
Nuxt , que fará isso por você? Nos meus projetos, eu também o usei, mas em projetos simples isso pode ser redundante. Além disso, ninguém cancelou projetos com código legado que caem sobre você como neve em sua cabeça. E conecte a estrutura lá - praticamente faça isso do zero.
Mastermind
O organizador dessa organização foi Nuxt. Foi usado por mim em um grande projeto com o Vue.
O Nuxt tem um ótimo recurso - plugins. Cada plug-in é um arquivo que exporta uma função. A configuração é passada para a função, que também será passada para o construtor Vue ao criar a instância, bem como para toda a
loja .
Além disso, um recurso extremamente útil,
inject
está disponível em cada plug-in. Faz uma injeção de dependência na instância raiz do Vue e no objeto de
store
. E isso significa que em cada componente, em cada função de armazenamento, a dependência especificada estará disponível por meio
this
.
Onde isso pode ser útil?
Além do fato de o
main.js
"perder peso significativamente", você também terá a oportunidade de usar a dependência em qualquer lugar do aplicativo, sem importações desnecessárias.
Um excelente exemplo de injeção de dependência é o
vue-router . Não é usado com muita frequência - para obter os parâmetros da rota atual, fazer um redirecionamento, mas essa é uma dependência global. Se ele pode ser útil em qualquer componente, por que não torná-lo global? Além disso, graças a isso, seu estado também será armazenado globalmente e alterado para todo o aplicativo.
Outro exemplo é
vue-wait . Os desenvolvedores deste plug-in foram além e adicionaram a propriedade
$wait
não apenas à instância do Vue, mas também à loja do vuex. Dadas as especificidades do plug-in, isso se mostra extremamente útil. Por exemplo, a loja possui uma ação chamada em vários componentes. E em cada caso, você precisa mostrar o carregador em algum elemento. Em vez de chamar
$wait.start('action')
e
$wait.end('action')
antes e depois de cada chamada de ação, você pode simplesmente chamar esses métodos uma vez na própria ação. E isso é muito mais legível e menos detalhado que o
dispatch('wait/start', 'action' {root: true})
. No caso da loja, isso é açúcar sintático.
Das palavras ao código
A estrutura básica do projeto
Vamos ver como é o projeto agora:
src
- store
- App.vue
- main.js
main.js
parece com isso:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; new Vue({ render: h => h(App), store }).$mount('#app');
Nós conectamos a primeira dependência
Agora queremos conectar
axios ao nosso projeto e criar algum tipo de configuração para ele. Segui a terminologia do Nuxt e criei um diretório de
plugins
no
src
. Dentro do diretório estão os
axios.js
index.js
e
axios.js
.
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
Como mencionado acima, cada plug-in deve exportar uma função. Ao mesmo tempo, dentro da função, queremos ter acesso à loja e, posteriormente, a função
inject
.
axios.js
import axios from 'axios'; export default function (app) {
index.js
:
import Vue from 'vue'; import axios from './axios'; export default function (app) { let inject = () => {};
Como você pode ver, o arquivo
index.js
também exporta a função. Isso é feito para poder passar o objeto do
app
lá. Agora vamos mudar
main.js
e chamar essa função.
main.js
:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; import initPlugins from './plugins';
Resultado
Nesse estágio, conseguimos remover a configuração do plugin do
main.js
em um arquivo separado.
A propósito, o benefício de passar o objeto do
app
para todos os nossos plugins é que, dentro de cada plug-in, agora temos acesso à loja. Você pode usá-lo livremente chamando
commit
,
dispatch
, além de acessar
store.state
e
store.getters
.
Se você gosta do estilo ES6, pode até fazer o seguinte:
axios.js
import axios from 'axios'; export default function ({store: {dispatch, commit, state, getters}}) { ... }
Segunda Etapa - Injeção de Dependência
Já criamos o primeiro plugin e agora nosso projeto se parece com o seguinte:
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
Como na maioria das bibliotecas onde é realmente necessário, a Injeção de Dependência já está implementada usando o
Vue.use
, criaremos nosso próprio plugin simples.
Por exemplo, tente repetir o que o
vue-wait
faz. Essa é uma biblioteca bastante pesada; portanto, se você quiser mostrar o carregador em um par de botões, é melhor abandoná-lo. No entanto, não pude resistir à sua conveniência e repeti em seu projeto sua funcionalidade básica, incluindo açúcar sintático na loja.
Aguarde plugin
Crie outro arquivo no diretório
plugins
-
wait.js
Eu já tenho um módulo vuex, que também chamei de
wait
. Ele executa três etapas simples:
-
start
- define a propriedade state de um objeto chamado
action
como
true
-
end
- remove do estado uma propriedade de um objeto chamado
action
-
is
- obtém do estado uma propriedade de um objeto chamado
action
Neste plugin, vamos usá-lo.
wait.js
export default function ({store: {dispatch, getters}}, inject) { const wait = { start: action => dispatch('wait/start', action), end: action => dispatch('wait/end', action), is: action => getters['wait/waiting'](action) }; inject('wait', wait); }
E conecte nosso plugin:
index.js
:
import Vue from 'vue'; import axios from './axios'; import wait from './wait'; export default function (app) { let inject = () => {}; Injection axios(app, inject); wait(app, inject); }
Injetar função
Agora implementamos a função
inject
.
A magia do Vue.prototype
Agora sobre magia. A
documentação do Vue diz que é suficiente escrever
Vue.prototype.$appName = ' ';
e
$appName
estarão disponíveis
this
.
No entanto, na realidade, descobriu-se que não é assim. Devido à pesquisa no Google, não houve resposta por que esse design não funcionou. Portanto, decidi entrar em contato com os autores do plugin que já implementaram isso.
Global mixin
Como no nosso exemplo, observei o código do plugin
vue-wait
. Eles oferecem essa implementação (o código-fonte é limpo para maior clareza):
Vue.mixin({ beforeCreate() { const { wait, store } = this.$options; let instance = null; instance.init(Vue, store);
Em vez de um protótipo, propõe-se o uso de uma mixina global. O efeito é basicamente o mesmo, talvez, com exceção de algumas nuances. Mas, como o injetor é feito aqui, não parece exatamente o caminho certo e não corresponde ao descrito na documentação.
Mas e se o protótipo?
A idéia por trás da solução de protótipo usada no
inject
função de
inject
foi emprestada do Nuxt. Parece muito mais correto do que o mixin global, então decidi.
Vue.use(() => {
Resultado
Após essas manipulações, temos a oportunidade de acessar
this.$wait
partir de qualquer componente, bem como de qualquer método na loja.
O que aconteceu
Estrutura do projeto:
src
- plugins
-- index.js
-- axios.js
-- wait.js
- store
- App.vue
- main.js
index.js
:
import Vue from 'vue'; import axios from './axios'; import wait from './wait'; export default function (app) { let inject = (name, plugin) => { let key = `$${name}`; app[key] = plugin; app.store[key] = plugin; Vue.use(() => { if (Vue.prototype.hasOwnProperty(key)) { return; } Object.defineProperty(Vue.prototype, key, { get () { return this.$root.$options[key]; } }); }); }; axios(app, inject); wait(app, inject); }
wait.js
export default function ({store: {dispatch, getters}}, inject) { const wait = { start: action => dispatch('wait/start', action), end: action => dispatch('wait/end', action), is: action => getters['wait/waiting'](action) }; inject('wait', wait); }
axios.js
import axios from 'axios'; export default function (app) { axios.defaults.baseURL = process.env.API_BASE_URL; axios.defaults.headers.common['Accept'] = 'application/json'; axios.defaults.headers.post['Content-Type'] = 'application/json'; }
main.js
:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; import initPlugins from './plugins'; const app = { render: h => h(App), store }; initPlugins(app); new Vue(app).$mount('#app');
Conclusão
Como resultado das manipulações, recebemos uma importação e uma chamada de função no arquivo
main.js
E agora fica imediatamente claro onde procurar a configuração para cada plug-in e cada dependência global.
Ao adicionar um novo plugin, você só precisa criar um arquivo que exporte a função, importá-lo para
index.js
e chamar essa função.
Na minha prática, essa estrutura provou ser muito conveniente, além disso, é facilmente transferida de projeto para projeto. Agora não há problema se você precisar fazer a injeção de dependência ou configurar outro plug-in.
Compartilhe sua experiência com o gerenciamento de dependências nos comentários. Projetos de sucesso!