Використовуйте будь-яку бібліотеку з JS Vue.js

326

Від автора: 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..’);
}
})