Jeder, der mit Vue vertraut ist, weiß, dass eine Vue-Anwendung einen Einstiegspunkt hat - die Datei
main.js
Dort gibt es neben dem Erstellen einer Instanz von Vue einen Import und eine Art Abhängigkeitsinjektion aller Ihrer globalen Abhängigkeiten (Direktiven, Komponenten, Plugins). Je größer das Projekt, desto mehr Abhängigkeiten werden, die darüber hinaus jeweils ihre eigene Konfiguration haben. Als Ergebnis erhalten wir eine große Datei mit allen Konfigurationen.
In diesem Artikel wird erläutert, wie Sie globale Abhängigkeiten organisieren, um dies zu vermeiden.

Warum selbst schreiben?
Viele mögen denken - warum ist das notwendig, wenn es zum Beispiel
Nuxt gibt , das dies für Sie
erledigt ? In meinen Projekten habe ich es auch verwendet, aber in einfachen Projekten kann dies überflüssig sein. Darüber hinaus hat niemand Projekte mit Legacy-Code abgebrochen, die wie Schnee auf Ihrem Kopf auf Sie fallen. Und schließen Sie das Framework dort an - praktisch von Grund auf neu.
Mastermind
Der Organisator einer solchen Organisation war Nuxt. Es wurde von mir bei einem großen Projekt mit Vue verwendet.
Nuxt hat eine großartige Funktion - Plugins. Jedes Plugin ist eine Datei, die eine Funktion exportiert. Die Konfiguration wird an die Funktion übergeben, die beim Erstellen der Instanz auch an den Vue-Konstruktor sowie an den gesamten
Speicher übergeben wird .
Darüber hinaus ist in jedem Plugin eine äußerst nützliche Funktion,
inject
verfügbar. Es wird eine Abhängigkeitsinjektion für die Stamminstanz von Vue und für das
store
. Dies bedeutet, dass in jeder Komponente, in jeder Speicherfunktion die angegebene Abhängigkeit dadurch verfügbar ist.
Wo kann das nützlich sein?
Zusätzlich zu der Tatsache, dass
main.js
erheblich „abnehmen“, erhalten Sie auch die Möglichkeit, die Abhängigkeit überall in der Anwendung ohne unnötige Importe zu verwenden.
Ein Paradebeispiel für Dependency Injection ist der
Vue-Router . Es wird nicht sehr oft verwendet - um die Parameter der aktuellen Route abzurufen, um eine Umleitung durchzuführen, aber dies ist eine globale Abhängigkeit. Wenn es in einer Komponente nützlich sein kann, warum nicht global machen? Dank dessen wird der Status außerdem global gespeichert und für die gesamte Anwendung geändert.
Ein weiteres Beispiel ist
vue-wait . Die Entwickler dieses Plugins gingen noch weiter und fügten die
$wait
Eigenschaft nicht nur der Vue-Instanz, sondern auch dem Vuex-Store hinzu. Angesichts der Besonderheiten des Plugins erweist sich dies als äußerst nützlich. Beispielsweise verfügt der Speicher über eine Aktion, die für mehrere Komponenten aufgerufen wird. In jedem Fall müssen Sie den Loader für ein Element anzeigen. Anstatt vor und nach jedem Aktionsaufruf
$wait.start('action')
und
$wait.end('action')
aufzurufen, können Sie diese Methoden einfach einmal in der Aktion selbst aufrufen. Und dies ist viel lesbarer und weniger ausführlich als der
dispatch('wait/start', 'action' {root: true})
. Im Falle eines Geschäfts ist dies syntaktischer Zucker.
Von Wörtern zu Code
Die Grundstruktur des Projekts
Mal sehen, wie das Projekt jetzt aussieht:
src
- store
- App.vue
- main.js
main.js
sieht
main.js
aus:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; new Vue({ render: h => h(App), store }).$mount('#app');
Wir verbinden die erste Abhängigkeit
Jetzt wollen wir
Axios mit unserem Projekt verbinden und eine Konfiguration dafür erstellen. Ich folgte der Nuxt-Terminologie und erstellte ein
plugins
Verzeichnis in
src
. Im Verzeichnis befinden sich die
axios.js
index.js
und
axios.js
.
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
Wie oben erwähnt, muss jedes Plugin eine Funktion exportieren. Gleichzeitig möchten wir innerhalb der Funktion Zugriff auf den Speicher und anschließend auf die
inject
Funktion haben.
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 = () => {};
Wie Sie sehen können, exportiert die Datei
index.js
auch die Funktion. Dies geschieht, um das
app
Objekt dort übergeben zu können. Lassen Sie uns nun
main.js
ändern und diese Funktion aufrufen.
main.js
:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; import initPlugins from './plugins';
Ergebnis
Zu diesem Zeitpunkt haben wir erreicht, dass wir die Plugin-Konfiguration aus
main.js
in einer separaten Datei entfernt haben.
Der Vorteil der Übergabe des
app
Objekts an alle unsere Plugins besteht übrigens darin, dass wir in jedem Plugin jetzt Zugriff auf den Store haben. Sie können es frei verwenden, indem Sie
commit
und
dispatch
aufrufen sowie auf
store.state
und
store.getters
.
Wenn Sie ES6-Stil mögen, können Sie dies sogar tun:
axios.js
import axios from 'axios'; export default function ({store: {dispatch, commit, state, getters}}) { ... }
Zweite Stufe - Abhängigkeitsinjektion
Wir haben bereits das erste Plugin erstellt und jetzt sieht unser Projekt so aus:
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
Da in den meisten Bibliotheken, in denen dies wirklich erforderlich ist, Dependency Injection bereits mit
Vue.use
implementiert ist,
Vue.use
wir unser eigenes einfaches Plugin.
Versuchen Sie beispielsweise zu wiederholen, was
vue-wait
tut. Dies ist eine ziemlich umfangreiche Bibliothek. Wenn Sie also den Loader auf zwei Schaltflächen anzeigen möchten, ist es besser, ihn zu verlassen. Ich konnte jedoch seiner Bequemlichkeit nicht widerstehen und wiederholte in seinem Projekt seine grundlegende Funktionalität, einschließlich des syntaktischen Zuckers im Laden.
Warten Sie Plugin
Erstellen Sie eine weitere Datei im
plugins
Verzeichnis -
wait.js
Ich habe bereits ein Vuex-Modul, das ich auch
wait
. Er macht drei einfache Schritte:
-
start
- setzt die state-Eigenschaft eines Objekts mit dem Namen
action
auf
true
-
end
- Entfernt eine Eigenschaft eines Objekts mit dem Namen
action
aus dem Status
-
is
- ruft vom Status eine Eigenschaft eines Objekts mit dem Namen
action
In diesem Plugin werden wir es verwenden.
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); }
Und verbinden Sie unser 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); }
Injizieren Sie die Funktion
Jetzt implementieren wir die
inject
Funktion.
Die Magie von Vue.prototype
Nun zur Magie. Die
Vue-Dokumentation besagt, dass es ausreicht,
Vue.prototype.$appName = ' ';
zu schreiben
Vue.prototype.$appName = ' ';
und
$appName
werden hier verfügbar sein.
In Wirklichkeit stellte sich jedoch heraus, dass dies nicht der Fall ist. Aufgrund von Googeln gab es keine Antwort, warum ein solches Design nicht funktionierte. Daher habe ich mich entschlossen, die Autoren des Plugins zu kontaktieren, die dies bereits implementiert haben.
Globales Mixin
Wie in unserem Beispiel habe ich mir den
vue-wait
Plugin-Code angesehen. Sie bieten eine solche Implementierung an (der Quellcode wird aus Gründen der Übersichtlichkeit bereinigt):
Vue.mixin({ beforeCreate() { const { wait, store } = this.$options; let instance = null; instance.init(Vue, store);
Anstelle eines Prototyps wird vorgeschlagen, ein globales Mixin zu verwenden. Der Effekt ist vielleicht im Grunde der gleiche, vielleicht mit Ausnahme einiger Nuancen. Da die Injektion jedoch hier im Geschäft erfolgt, sieht sie nicht genau richtig aus und entspricht überhaupt nicht der Dokumentation.
Aber was ist, wenn Prototyp?
Die Idee hinter der im
inject
verwendeten Prototyplösung wurde von Nuxt übernommen. Es sieht viel richtiger aus als das globale Mixin, also habe ich mich darauf festgelegt.
Vue.use(() => {
Ergebnis
Nach diesen Manipulationen erhalten wir die Möglichkeit, darauf zuzugreifen
this.$wait
von jeder Komponente sowie von jeder Methode im Geschäft.
Was ist passiert?
Projektstruktur:
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');
Fazit
Als Ergebnis der Manipulationen haben wir einen Import- und einen Funktionsaufruf in der Datei
main.js
. Und jetzt ist sofort klar, wo für jedes Plugin und jede globale Abhängigkeit nach der Konfiguration gesucht werden muss.
Wenn Sie ein neues Plugin hinzufügen, müssen Sie nur eine Datei erstellen, die die Funktion exportiert, in
index.js
und diese Funktion aufrufen.
In meiner Praxis hat sich eine solche Struktur als sehr praktisch erwiesen, außerdem kann sie leicht von Projekt zu Projekt übertragen werden. Jetzt gibt es keine Schmerzen mehr, wenn Sie Dependency Injection ausführen oder ein anderes Plugin konfigurieren müssen.
Teilen Sie Ihre Erfahrungen mit dem Abhängigkeitsmanagement in den Kommentaren mit. Erfolgreiche Projekte!