Todos los que están familiarizados con Vue saben que una aplicación Vue tiene un punto de entrada: el archivo
main.js
Allí, además de crear una instancia de Vue, hay una importación y una especie de inyección de dependencia de todas sus dependencias globales (directivas, componentes, complementos). Cuanto más grande es el proyecto, más dependencias se vuelven, lo que, además, cada uno tiene su propia configuración. Como resultado, obtenemos un archivo enorme con todas las configuraciones.
Este artículo discutirá cómo organizar dependencias globales para evitar esto.

¿Por qué escribirlo tú mismo?
Muchos pueden pensar: ¿por qué es esto necesario si hay, por ejemplo,
Nuxt , que hará esto por usted? En mis proyectos, también lo usé, pero en proyectos simples esto puede ser redundante. Además, nadie ha cancelado proyectos con código heredado que caen sobre ti como la nieve en tu cabeza. Y conecte el marco allí, prácticamente hágalo desde cero.
Mente maestra
El organizador de tal organización fue Nuxt. Lo usé en un gran proyecto con Vue.
Nuxt tiene una gran característica: complementos. Cada complemento es un archivo que exporta una función. La configuración se pasa a la función, que también se pasará al constructor Vue al crear la instancia, así como a toda la
tienda .
Además, una característica extremadamente útil,
inject
está disponible en cada complemento. Realiza una inyección de dependencia a la instancia raíz de Vue y al objeto de la
store
. Y esto significa que en cada componente, en cada función de almacenamiento, la dependencia especificada estará disponible a través de
this
.
¿Dónde puede ser útil esto?
Además del hecho de que
main.js
"pierde peso" significativamente, también tendrá la oportunidad de utilizar la dependencia en cualquier lugar de la aplicación sin importaciones innecesarias.
Un buen ejemplo de inyección de dependencias es
vue-router . No se usa con mucha frecuencia: para obtener los parámetros de la ruta actual, para hacer una redirección, pero esta es una dependencia global. Si puede ser útil en cualquier componente, ¿por qué no hacerlo global? Además, gracias a esto, su estado también se almacenará globalmente y cambiará para toda la aplicación.
Otro ejemplo es
vue-wait . Los desarrolladores de este complemento fueron más allá y agregaron la propiedad
$wait
no solo a la instancia de Vue, sino también a la tienda vuex. Dados los detalles del complemento, esto demuestra ser extremadamente útil. Por ejemplo, la tienda tiene una acción que se llama en varios componentes. Y en cada caso, debe mostrar el cargador en algún elemento. En lugar de llamar a
$wait.start('action')
y
$wait.end('action')
antes y después de cada llamada a la acción, simplemente puede llamar a estos métodos una vez en la acción misma. Y esto es mucho más legible y menos detallado que el
dispatch('wait/start', 'action' {root: true})
. En el caso de la tienda, este es el azúcar sintáctico.
De las palabras al código
La estructura básica del proyecto.
Veamos cómo se ve el proyecto ahora:
src
- store
- App.vue
- main.js
main.js
parece a esto:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; new Vue({ render: h => h(App), store }).$mount('#app');
Conectamos la primera dependencia
Ahora queremos conectar
axios a nuestro proyecto y crear algún tipo de configuración para él. Seguí la terminología de Nuxt y creé un directorio de
plugins
en
src
. Dentro del directorio hay
axios.js
index.js
y
axios.js
.
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
Como se mencionó anteriormente, cada complemento debe exportar una función. Al mismo tiempo, dentro de la función queremos tener acceso a la tienda y, posteriormente, a la función de
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 puede ver, el archivo
index.js
también exporta la función. Esto se hace para poder pasar el objeto de la
app
allí. Ahora
main.js
y llamemos a esta función.
main.js
:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; import initPlugins from './plugins';
Resultado
En esta etapa, hemos logrado eliminar la configuración del complemento de
main.js
en un archivo separado.
Por cierto, el beneficio de pasar el objeto de la
app
a todos nuestros complementos es que dentro de cada complemento ahora tenemos acceso a la tienda. Puede usarlo libremente llamando a
commit
,
dispatch
y accediendo a
store.state
y
store.getters
.
Si te gusta el estilo ES6, incluso puedes hacer esto:
axios.js
import axios from 'axios'; export default function ({store: {dispatch, commit, state, getters}}) { ... }
Segunda etapa: inyección de dependencia
Ya hemos creado el primer complemento y ahora nuestro proyecto se ve así:
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
Dado que en la mayoría de las bibliotecas donde es realmente necesario, la Inyección de dependencias ya está implementada usando
Vue.use
, crearemos nuestro propio complemento simple.
Por ejemplo, intente repetir lo que hace
vue-wait
. Esta es una biblioteca bastante pesada, por lo que si desea mostrar el cargador en un par de botones, es mejor abandonarlo. Sin embargo, no pude resistir su conveniencia y repetí en su proyecto su funcionalidad básica, incluido el azúcar sintáctico en la tienda.
Esperar complemento
Cree otro archivo en el directorio de
plugins
-
wait.js
Ya tengo un módulo vuex, al que también llamé
wait
. Él hace tres pasos simples:
-
start
- establece la propiedad de estado de un objeto llamado
action
en
true
-
end
- elimina del estado una propiedad de un objeto llamado
action
-
is
- obtiene del estado una propiedad de un objeto llamado
action
En este complemento lo usaremos.
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); }
Y conecta nuestro complemento:
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); }
Función de inyección
Ahora implementamos la función de
inject
.
La magia del prototipo Vue.
Ahora sobre magia. La
documentación de Vue dice que es suficiente escribir
Vue.prototype.$appName = ' ';
y
$appName
estará disponible en
this
.
Sin embargo, en realidad resultó que esto no es así. Debido a googlear, no hubo respuesta por qué tal diseño no funcionó. Por lo tanto, decidí contactar a los autores del complemento que ya lo implementaron.
Mixin global
Como en nuestro ejemplo, miré el código del complemento
vue-wait
. Ofrecen dicha implementación (el código fuente se limpia para mayor claridad):
Vue.mixin({ beforeCreate() { const { wait, store } = this.$options; let instance = null; instance.init(Vue, store);
En lugar de un prototipo, se propone utilizar un mixin global. El efecto es básicamente el mismo, quizás, con la excepción de algunos matices. Pero dado que la inyección se realiza en la tienda aquí, no se ve exactamente de la manera correcta y no corresponde en absoluto a la documentación.
Pero, ¿y si el prototipo?
La idea detrás de la solución prototipo utilizada en el
inject
función de
inject
fue tomada de Nuxt. Parece mucho más correcto que el mixin global, así que me decidí por él.
Vue.use(() => {
Resultado
Después de estas manipulaciones, tenemos la oportunidad de acceder a
this.$wait
desde cualquier componente, así como desde cualquier método en la tienda.
Que paso
Estructura del proyecto:
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');
Conclusión
Como resultado de las manipulaciones, recibimos una llamada de importación y una función en el archivo
main.js
Y ahora está claro de inmediato dónde buscar la configuración para cada complemento y cada dependencia global.
Al agregar un nuevo complemento, solo necesita crear un archivo que exporte la función, importarlo en
index.js
y llamar a esta función.
En mi práctica, dicha estructura ha demostrado ser muy conveniente, además, se transfiere fácilmente de un proyecto a otro. Ahora no hay dolor si necesita hacer una inyección de dependencia o configurar otro complemento.
Comparta su experiencia con la gestión de dependencias en los comentarios. Proyectos exitosos!