Від автора: Lodash, Moment, Axios, Async… ці корисні бібліотеки JS ви хотіли б використовувати в багатьох своїх додатках Vue.js. Однак по мірі зростання проекту ви будете розділяти код на файл компонентів і файли модулів. Може, ви захочете запускати додаток на різних машинах, щоб використовувати функцію серверного рендера. Якщо ви не знайдете простий і надійний спосіб підключити ці JS бібліотеки компоненти та модулі, буде неприємно!
Як не варто підключати бібліотеку в Vue.js проект
Глобальна змінна
Наївний спосіб додати бібліотеку в проект – зробити її глобальної змінної, причепивши до об’єкта window:
entry.js
window._ = require(‘lodash’);
MyComponent.vue
export default {
created() {
console.log(_.isEmpty() ? ‘Lodash everywhere!’ : ‘Uh oh..’);
}
}
Спосіб без window змінних довгий, і там не працює серверний рендер. Коли додаток запускається на сервері, об’єкт window буде undefined. Тому ви не зможете отримати його властивості, ви отримаєте помилку.
Імпорт у всі файли
Ще один другосортний метод – імпорт бібліотеки файли:
MyComponent.vue
import _ from ‘lodash’;
export default {
created() {
console.log(_.isEmpty() ? ‘Lodash is available here!’ : ‘Uh oh..’);
}
}
Спосіб працює, але не дотримується підхід DRY, так і складно це: вам потрібно пам’ятати про імпорт у всі файли, а також видаляти імпорт, якщо ви більше не використовуєте цей файл. Якщо ви погано налаштуєте свій білд інструмент, то отримаєте безліч копій однієї і тієї ж бібліотеки в билде.
Спосіб краще
Самий чистий і надійний спосіб використовувати JS бібліотеку в Vue проекті – проксировать його властивість об’єкта прототипу Vue. Зробимо це і додамо бібліотеку дати і часу Moment в наш проект:
entry.js
import moment from ‘moment’;
Object.definePrototype(Vue.prototype, ‘$moment’, { value: moment });
Всі компоненти успадковують методи від об’єкта прототипу Vue, тому Moment автоматично доступний відразу в усіх компонентах без глобальних змінних або ручних импортов. Бібліотека доступна через будь-який об’єкт/компонент через this.$moment:
MyNewComponent.vue
export default {
created() {
console.log(‘The time is’ . this.$moment().format(“HH:mm”));
}
}
Давайте розберемо, як тут все працює.
Object.defineProperty
Зазвичай властивість об’єкта задається так:
Vue.prototype.$moment = moment;
Можна зробити й так, проте з допомогою Object.defineProperty ми можемо задавати властивість через дескриптор. Дескриптор дозволяє встановлювати низькорівневі деталі, такі як можливість перезаписувати властивість, а також можливість видимості при перерахуванні в циклі for.
Зазвичай нам такі можливості не потрібні, тому що в 99% випадків нам не потрібна така деталізація з призначенням властивостей. Але тут ми отримуємо перевага: властивості, створені через дескриптор, за замовчуванням доступні тільки для читання.
Це означає, що якийсь розробник (можливо ви) не зможе зробити щось дурне в компоненті і зламати всі:
this.$http = ‘Assign some random thing to the instance method’;
this.$http.get(‘/’); // TypeError: this.$http.get is not a function
Наш read-only метод об’єкта захищає бібліотеку. Якщо ви спробуєте перезаписати її, то отримаєте «TypeError: Cannot assign to read only property».
$
Зверніть увагу, що ми проксируем нашу бібліотеку в властивість з префіксом $. Ви також можете помітити інші властивості і методи типу $refs, $on, $mount і т. д., у яких теж є цей префікс.
Префікс не обов’язковий, але він додається до властивостей як нагадування розробникам, що це публічне API властивість або метод, на відміну від інших властивостей об’єкта, призначених для внутрішнього використання в Vue.
Мова JS заснований на прототипах, тому в ньому немає реальних класів, а значить, і немає private і public змінних і статичних методів. Такий тип оголошення є м’яким замінником, але мені здається, варто його дотримуватися.
this
Також зверніть увагу, що для роботи з бібліотекою необхідно використовувати this.libraryName, що не дивно, адже це тепер метод об’єкта.
Один наслідок – на відміну від глобальної змінної, ви зобов’язані знати, що знаходитесь в правильному області видимості при використанні бібліотеки. Всередині колбеков не можна використовувати this.
Колбеки подвійними стрілками – хороший спосіб переконатися, що ви залишилися в правильній області видимості:
this.$http.get(‘/’).then(res => {
if (res.status !== 200) {
this.$http.get(‘/’) // etc
// Only works in a fat arrow callback.
}
});
Чому не перетворити її в плагін?
Якщо плануєте використовувати бібліотеку в декількох Vue проектах або хочете поділитися нею зі світом, можете зробити свій плагін!
Плагін абстрагує складність та дозволяє робити наступне в проекті для додавання обраної бібліотеки:
import MyLibraryPlugin from ‘my-library-plugin’;
Vue.use(MyLibraryPlugin);
Ці два рядки дозволяють використовувати бібліотеку в будь-якому компоненті так само, як з Vue Router, Vuex та іншими плагінами, що використовують Vue.use.
Написання плагіна
Спершу створіть файл плагіна. У цьому прикладі я зроблю плагін, який додає Axios у всі об’єкти Vue і компоненти, тому назву файл axios.js.
Головне зрозуміти, що плагін повинен володіти методом install, які беруть конструкторVue в якості першого аргументу.
axios.js
export default {
install: function(Vue) {
// Do stuff
}
}
Тепер ми можемо використовувати наш попередній метод для додавання бібліотеки в об’єкт прототипу:
axios.js
import axios from ‘axios’;
export default {
install: function(Vue,) {
Object.defineProperty(Vue.prototype, ‘$http’, { value: axios });
}
}
Метод use об’єкта – все що потрібно, щоб додати нашу бібліотеку в проект. Наприклад, тепер можна додати бібліотеку Axios:
entry.js
import AxiosPlugin from ‘./axios.js’;
Vue.use(AxiosPlugin);
new Vue({
created() {
console.log(this.$http ? ‘Axios works!’ : ‘Uh oh..’);
}
})
Бонус: необов’язкові аргументи плагіна
Метод install плагіна може приймати необов’язкові аргументи. Деяким розробникам не сподобається викликати метод $http об’єкта Axios, так як зазвичай дають ім’я Vue Resource. Тому давайте з допомогою додаткового аргументу дозволимо їм змінювати ім’я:
axios.js
import axios from ‘axios’;
export default {
install: function(Vue, name = ‘$http’) {
Object.defineProperty(Vue.prototype, name, { value: axios });
}
}
entry.js
import AxiosPlugin from ‘./axios.js’;
Vue.use(AxiosPlugin, ‘$axios’);
new Vue({
created() {
console.log(this.$axios ? ‘Axios works!’ : ‘Uh oh..’);
}
})