Semua orang yang mengenal Vue tahu bahwa aplikasi Vue memiliki satu titik masuk - file
main.js
Di sana, selain membuat instance Vue, ada impor dan semacam Injeksi Ketergantungan dari semua dependensi global Anda (arahan, komponen, plugin). Semakin besar proyek, semakin banyak ketergantungan menjadi, yang, apalagi, masing-masing memiliki konfigurasi sendiri. Hasilnya, kami mendapatkan satu file besar dengan semua konfigurasi.
Artikel ini akan membahas cara mengatur dependensi global untuk menghindari hal ini.

Mengapa menulisnya sendiri?
Banyak yang mungkin berpikir - mengapa ini perlu jika ada, misalnya,
Nuxt , yang akan melakukan ini untuk Anda? Dalam proyek saya, saya juga menggunakannya, tetapi dalam proyek sederhana ini mungkin berlebihan. Selain itu, tidak ada yang membatalkan proyek dengan kode lawas yang jatuh pada Anda seperti salju di kepala Anda. Dan hubungkan kerangka kerja di sana - praktis melakukannya dari awal.
Dalang
Penyelenggara organisasi semacam itu adalah Nuxt. Itu digunakan oleh saya pada proyek besar dengan Vue.
Nuxt memiliki fitur hebat - plugin. Setiap plugin adalah file yang mengekspor suatu fungsi. Konfigurasi dilewatkan ke fungsi, yang juga akan diteruskan ke konstruktor Vue saat membuat instance, serta seluruh
toko .
Selain itu, fitur yang sangat berguna,
inject
tersedia di setiap plugin. Itu membuat Dependency Injection ke instance root dari Vue dan ke objek
store
. Dan ini berarti bahwa dalam setiap komponen, dalam setiap fungsi penyimpanan, ketergantungan yang ditentukan akan tersedia melalui
this
.
Di mana ini bisa berguna?
Selain fakta bahwa
main.js
secara signifikan menurunkan berat badan, Anda juga akan mendapatkan kesempatan untuk menggunakan dependensi di mana saja dalam aplikasi tanpa impor yang tidak perlu.
Contoh utama dari Dependency Injection adalah
vue-router . Ini tidak sering digunakan - untuk mendapatkan parameter dari rute saat ini, untuk membuat arahan ulang, tetapi ini adalah ketergantungan global. Jika itu bisa berguna dalam komponen apa pun, lalu mengapa tidak membuatnya global? Selain itu, berkat ini, kondisinya juga akan disimpan secara global dan diubah untuk seluruh aplikasi.
Contoh lain adalah
vue-wait . Pengembang plugin ini melangkah lebih jauh dan menambahkan properti
$wait
tidak hanya ke instance Vue, tetapi juga ke toko vuex. Mengingat spesifikasi plugin yang spesifik, ini terbukti sangat berguna. Misalnya, toko memiliki tindakan yang disebut pada beberapa komponen. Dan dalam setiap kasus, Anda perlu menunjukkan loader pada beberapa elemen. Alih-alih memanggil
$wait.start('action')
dan
$wait.end('action')
sebelum dan setelah setiap panggilan aksi, Anda dapat memanggil metode ini sekali saja dalam aksi itu sendiri. Dan ini jauh lebih mudah dibaca dan lebih sedikit verbose daripada
dispatch('wait/start', 'action' {root: true})
. Dalam hal toko, ini adalah gula sintaksis.
Dari kata ke kode
Struktur dasar proyek
Mari kita lihat seperti apa proyek itu sekarang:
src
- store
- App.vue
- main.js
main.js
terlihat seperti ini:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; new Vue({ render: h => h(App), store }).$mount('#app');
Kami menghubungkan ketergantungan pertama
Sekarang kami ingin menghubungkan
aksioma ke proyek kami dan membuat semacam konfigurasi untuknya. Saya mengikuti terminologi Nuxt dan membuat direktori
plugins
di
src
. Di dalam direktori terdapat
axios.js
index.js
dan
axios.js
.
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
Seperti disebutkan di atas, setiap plugin harus mengekspor fungsi. Pada saat yang sama, di dalam fungsi kami ingin memiliki akses ke toko dan fungsi
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 = () => {};
Seperti yang Anda lihat, file
index.js
juga mengekspor fungsi. Ini dilakukan agar dapat melewati objek
app
sana. Sekarang mari kita ubah
main.js
dan panggil fungsi ini.
main.js
:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; import initPlugins from './plugins';
Hasil
Pada tahap ini, kami telah mencapai bahwa kami menghapus konfigurasi plugin dari
main.js
dalam file terpisah.
Ngomong-ngomong, manfaat dari melewatkan objek
app
ke semua plugin kita adalah bahwa di dalam setiap plugin kita sekarang memiliki akses ke toko. Anda dapat menggunakannya dengan bebas dengan memanggil
commit
,
dispatch
, serta mengakses
store.state
dan
store.getters
.
Jika Anda menyukai gaya ES6, Anda bahkan dapat melakukan ini:
axios.js
import axios from 'axios'; export default function ({store: {dispatch, commit, state, getters}}) { ... }
Tahap Kedua - Injeksi Ketergantungan
Kami telah membuat plugin pertama dan sekarang proyek kami terlihat seperti ini:
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
Karena di sebagian besar perpustakaan di mana itu benar-benar diperlukan, Dependency Injection sudah diterapkan menggunakan
Vue.use
, kita akan membuat plugin sederhana kita sendiri.
Misalnya, coba ulangi apa yang
vue-wait
lakukan. Ini adalah perpustakaan yang agak berat, jadi jika Anda ingin menunjukkan loader pada sepasang tombol, lebih baik untuk meninggalkannya. Namun, saya tidak dapat menahan kenyamanannya dan mengulangi dalam proyeknya fungsi dasarnya, termasuk gula sintaksis di toko.
Tunggu plugin
Buat file lain di direktori
plugins
-
wait.js
Saya sudah memiliki modul vuex, yang juga saya sebut
wait
. Dia melakukan tiga langkah sederhana:
-
start
- set properti state dari objek bernama
action
menjadi
true
-
end
- menghapus dari properti properti dari suatu
action
bernama
action
-
is
- get from state properti dari objek bernama
action
Dalam plugin ini kita akan menggunakannya.
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); }
Dan hubungkan plugin kami:
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); }
Fungsi injeksi
Sekarang kami menerapkan fungsi
inject
.
Keajaiban Vue.prototype
Sekarang tentang sihir.
Dokumentasi Vue mengatakan cukup untuk menulis
Vue.prototype.$appName = ' ';
dan
$appName
akan tersedia untuk
this
.
Namun, pada kenyataannya ternyata tidak demikian. Karena googling, tidak ada jawaban mengapa desain seperti itu tidak berhasil. Oleh karena itu, saya memutuskan untuk menghubungi penulis plugin yang sudah menerapkan ini.
Mixin global
Seperti dalam contoh kita, saya melihat kode plugin
vue-wait
. Mereka menawarkan implementasi seperti itu (kode sumber dibersihkan untuk kejelasan):
Vue.mixin({ beforeCreate() { const { wait, store } = this.$options; let instance = null; instance.init(Vue, store);
Alih-alih prototipe, diusulkan untuk menggunakan mixin global. Efeknya pada dasarnya sama, mungkin, dengan pengecualian beberapa nuansa. Tetapi mengingat injeksi dilakukan di toko di sini, itu tidak terlihat persis dengan cara yang benar dan sama sekali tidak sesuai dengan dokumentasi.
Tapi bagaimana kalau prototipe?
Gagasan di balik solusi prototipe yang digunakan dalam
inject
fungsi
inject
dipinjam dari Nuxt. Kelihatannya jauh lebih benar daripada mixin global, jadi saya memutuskannya.
Vue.use(() => {
Hasil
Setelah manipulasi ini, kami mendapat kesempatan untuk mengaksesnya
this.$wait
dari komponen apa pun, serta metode apa pun di toko.
Apa yang terjadi
Struktur proyek:
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');
Kesimpulan
Sebagai hasil dari manipulasi kami menerima satu impor dan satu panggilan fungsi di file
main.js
Dan sekarang sudah jelas tempat untuk mencari konfigurasi untuk setiap plugin dan setiap ketergantungan global.
Saat menambahkan plugin baru, Anda hanya perlu membuat file yang mengekspor fungsi, impor ke
index.js
dan panggil fungsi ini.
Dalam praktik saya, struktur seperti itu telah terbukti sangat nyaman, apalagi, mudah ditransfer dari proyek ke proyek. Sekarang tidak ada rasa sakit jika Anda perlu melakukan Dependency Injection atau mengkonfigurasi plugin lain.
Bagikan pengalaman Anda dengan manajemen ketergantungan di komentar. Proyek yang berhasil!