Tous ceux qui connaissent Vue savent qu'une application Vue a un point d'entrée - le fichier
main.js
Là, en plus de créer une instance de Vue, il y a une importation et une sorte d'injection de dépendances de toutes vos dépendances globales (directives, composants, plugins). Plus le projet est volumineux, plus les dépendances deviennent importantes et, de plus, chacune a sa propre configuration. En conséquence, nous obtenons un énorme fichier avec toutes les configurations.
Cet article explique comment organiser les dépendances globales pour éviter cela.

Pourquoi l'écrire vous-même?
Beaucoup peuvent penser - pourquoi est-ce nécessaire s'il y a, par exemple,
Nuxt , qui fera cela pour vous? Dans mes projets, je l'ai également utilisé, mais dans les projets simples, cela peut être redondant. De plus, personne n'a annulé des projets avec du code hérité qui vous tombent dessus comme de la neige sur la tête. Et connectez le cadre là-bas - faites-le pratiquement à partir de zéro.
Mastermind
L'organisateur d'une telle organisation était Nuxt. Il a été utilisé par moi sur un grand projet avec Vue.
Nuxt a une grande fonctionnalité - plugins. Chaque plugin est un fichier qui exporte une fonction. La configuration est transmise à la fonction, qui sera également transmise au constructeur Vue lors de la création de l'instance, ainsi qu'au
magasin entier.
De plus, une fonctionnalité extrêmement utile,
inject
est disponible dans chaque plugin. Il effectue une injection de dépendance à l'instance racine de Vue et à l'objet de
store
. Et cela signifie que dans chaque composant, dans chaque fonction de stockage, la dépendance spécifiée sera disponible par
this
biais.
Où cela peut-il être utile?
En plus du fait que
main.js
"perd du poids" de
main.js
significative, vous aurez également la possibilité d'utiliser la dépendance n'importe où dans l'application sans importations inutiles.
Vue-router est un excellent exemple d'injection de dépendance. Il n'est pas utilisé très souvent - pour obtenir les paramètres de l'itinéraire actuel, pour faire une redirection, mais c'est une dépendance globale. S'il peut être utile dans n'importe quel composant, alors pourquoi ne pas le rendre mondial? De plus, grâce à cela, son état sera également stocké globalement et modifié pour l'ensemble de l'application.
Un autre exemple est la
vue-wait . Les développeurs de ce plugin sont allés plus loin et ont ajouté la propriété
$wait
non seulement à l'instance Vue, mais aussi à la boutique vuex. Compte tenu des spécificités du plugin, cela s'avère extrêmement utile. Par exemple, le magasin a une action qui est appelée sur plusieurs composants. Et dans chaque cas, vous devez montrer le chargeur sur un élément. Au lieu d'appeler
$wait.start('action')
et
$wait.end('action')
avant et après chaque appel d'action, vous pouvez simplement appeler ces méthodes une fois dans l'action elle-même. Et c'est beaucoup plus lisible et moins verbeux que
dispatch('wait/start', 'action' {root: true})
. Dans le cas du magasin, il s'agit de sucre syntaxique.
Des mots au code
La structure de base du projet
Voyons maintenant à quoi ressemble le projet:
src
- store
- App.vue
- main.js
main.js
ressemble à ceci:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; new Vue({ render: h => h(App), store }).$mount('#app');
Nous connectons la première dépendance
Maintenant, nous voulons connecter
axios à notre projet et créer une sorte de configuration pour celui-ci. J'ai suivi la terminologie Nuxt et créé un répertoire de
plugins
dans
src
. Le répertoire
axios.js
index.js
et
axios.js
.
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
Comme mentionné ci-dessus, chaque plugin doit exporter une fonction. Dans le même temps, à l'intérieur de la fonction, nous voulons avoir accès au magasin et par la suite à la fonction d'
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 = () => {};
Comme vous pouvez le voir, le fichier
index.js
exporte également la fonction. Ceci est fait afin de pouvoir y passer l'objet
app
. Maintenant,
main.js
et appelons cette fonction.
main.js
:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; import initPlugins from './plugins';
Résultat
À ce stade, nous avons réalisé que nous avons supprimé la configuration du plugin de
main.js
dans un fichier séparé.
Soit dit en passant, l'avantage de transmettre l'objet d'
app
à tous nos plugins est qu'à l'intérieur de chaque plugin, nous avons maintenant accès au magasin. Vous pouvez l'utiliser librement en appelant
commit
,
dispatch
, ainsi qu'en accédant à
store.state
et
store.getters
.
Si vous aimez le style ES6, vous pouvez même le faire:
axios.js
import axios from 'axios'; export default function ({store: {dispatch, commit, state, getters}}) { ... }
Deuxième étape - Injection de dépendance
Nous avons déjà créé le premier plugin et maintenant notre projet ressemble à ceci:
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
Étant donné que dans la plupart des bibliothèques où cela est vraiment nécessaire, l'injection de dépendance est déjà implémentée à l'aide de
Vue.use
, nous allons créer notre propre plugin simple.
Par exemple, essayez de répéter ce que fait
vue-wait
. C'est une bibliothèque assez lourde, donc si vous voulez montrer le chargeur sur une paire de boutons, il vaut mieux l'abandonner. Cependant, je n'ai pas pu résister à sa commodité et répété dans son projet sa fonctionnalité de base, y compris le sucre syntaxique dans le magasin.
Plugin d'attente
Créez un autre fichier dans le répertoire des
plugins
-
wait.js
J'ai déjà un module vuex, que j'ai aussi appelé
wait
. Il fait trois étapes simples:
-
start
- définit la propriété state d'un objet nommé
action
sur
true
-
end
- supprime de l'état une propriété d'un objet nommé
action
-
is
- obtient de l'état une propriété d'un objet nommé
action
Dans ce plugin, nous allons l'utiliser.
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); }
Et connectez notre 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); }
Fonction d'injection
Maintenant, nous implémentons la fonction
inject
.
La magie de Vue.prototype
Maintenant sur la magie. La
documentation Vue indique qu'il suffit d'écrire
Vue.prototype.$appName = ' ';
et
$appName
seront disponibles
this
.
Cependant, en réalité, il s'est avéré que ce n'est pas le cas. En raison de la recherche sur Google, il n'y avait aucune réponse pourquoi un tel design ne fonctionnait pas. J'ai donc décidé de contacter les auteurs du plugin qui l'ont déjà implémenté.
Mixin mondial
Comme dans notre exemple, j'ai regardé le code du plugin
vue-wait
. Ils offrent une telle implémentation (le code source est nettoyé pour plus de clarté):
Vue.mixin({ beforeCreate() { const { wait, store } = this.$options; let instance = null; instance.init(Vue, store);
Au lieu d'un prototype, il est proposé d'utiliser un mixin global. L'effet est fondamentalement le même, peut-être, à l'exception de certaines nuances. Mais étant donné que l'injection est effectuée dans le magasin ici, elle ne semble pas exactement dans le bon sens et ne correspond pas du tout à la documentation.
Et si c'était un prototype?
L'idée derrière la solution prototype utilisée dans le
inject
fonction d'
inject
été empruntée à Nuxt. Il semble beaucoup plus juste que le mixin mondial, alors je me suis installé.
Vue.use(() => {
Résultat
Après ces manipulations, nous avons l'opportunité d'y accéder
this.$wait
de n'importe quel composant, ainsi que de n'importe quelle méthode du magasin.
Qu'est-il arrivé?
Structure du projet:
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');
Conclusion
À la suite des manipulations, nous avons reçu une importation et un appel de fonction dans le fichier
main.js
Et maintenant, il est immédiatement clair où chercher la configuration pour chaque plugin et chaque dépendance globale.
Lors de l'ajout d'un nouveau plugin, il vous suffit de créer un fichier qui exporte la fonction, de l'importer dans
index.js
et d'appeler cette fonction.
Dans ma pratique, une telle structure s'est avérée très pratique, de plus, elle est facilement transférable d'un projet à l'autre. Maintenant, il n'y a plus de problème si vous devez faire l'injection de dépendances ou configurer un autre plugin.
Partagez votre expérience avec la gestion des dépendances dans les commentaires. Projets réussis!