Наш досвід міграції на Vue 3. Частина перша
Вітаю! Мене звати Данііл, і я є Front-end Team Lead в українській продуктовій компанії Webitel. У двох статтях я хочу поділитися нашим досвідом міграції з Vue 2 на Vue 3.
У цій статті ми розберемо сетинг, у якому все відбувалося, мотивацію до міграції, а також основні кроки, а у наступній статті ми поговоримо про підводні камені та неочевидні проблеми, з якими ми стикнулись під час міграції.
За пʼять років розвитку нової версії платформи ми побудували масштабну фронтенд-частину продукту з десятьма різноплановими клієнтськими застосунками: від доволі «типових» CRUD-реєстрів до конструктора візуальних діаграм та власної бібліотеки компонентів.
Наш фронтенд побудований на екосистемі Vue. Починали розробку ми з Vue 2, бандлером Webpack v4 і тест-раннером Jest, з яких ми з часом мігрували на Vue 3, Vite та Vitest.
Спойлер: ні про одну з цих міграцій — не шкодуємо :)
Що цікавого у Vue 3
То чому ми вирішили мігрувати? Розберемо докладніше всі оновлення.
Composition API
Composition API — це новий стиль написання Vue-компонентів. Найцікавіша і найсуттєвіша фіча нової версії Vue.
Наведу список її фічей та переваг.
- Перевикористання коду.
Перше і найважливіше: код, написаний з використанням Composition API — простий та зручний у перевикористанні. Це і є його перевагою над Options API.
Перевикористання коду відбувається шляхом так званих Composable-функцій: чогось подібного на React custom hooks, але з важливими для Vue відмінностями (на відміну від React custom hooks, Composable-функції викликаються лише один раз).
- Розв’язання проблем, повʼязаних з міксинами.
Також, в цьому контексті дуже важливо порівняти composables з міксинами, за допомогою яких перевикористовується код компонентів у Options API. Річ у тім, що міксини мають свої підводні камені: проблеми, які є непомітні у невеликих проєктах, проте дуже відчутні у великих. Коли ми використовуємо міксини у компоненті, то додаємо властивості, яких не бачимо у самому компоненті. Через це, якщо ми хочемо дослідити його поведінку, нам необхідно провалюватись у міксин, і шукати, що ж там і звідки береться.
Крім того, міксини ніяк не вберігають нас від колізій в іменах наших властивостей: властивості, описані в кількох міксинах, просто переписуються останнім. Для невеликого застосунку з цим цілком можна миритися: по міксину на компонент, все достатньо прозоро, та й дослідити просто. Але як тільки міксинів стає декілька, і, ще страшніше, вони починають комунікувати між собою — починаються завеликі проблеми.
З власного досвіду розповім, що у нас в одному з проєктів, «старішому», вкладеність міксинів досягала, у найгіршому випадку, п’яти рівнів (тобто, міксин, в міксині, в міксин і так далі). Розбиратися в цьому коді і важко, і страшно. Це просто пекло міксинів. З Composable-функціями такої проблеми немає, тому що кожне використання — прозоре. Адже ми самі обираємо, що хочемо «взяти» з того, що нам повертає функція, і самі обираємо, як його назвати.
- Гнучкіша організація коду.
Через відсутність конкретної структури, як в Options API, написання компонентів через Composition API більше нагадує звичайний скрипт: ми можемо довільно розміщати порядок ініціалізації, викликів тощо.
Це є одночасно і плюсом, і мінусом. Адже, з одного боку, дозволяє групувати код за тим, що він робить, а не за тим, чим він є («data» окремо, «computed» окремо тощо) — що є доволі логічним. З іншого боку, забирає каркас структури компонента Options API, а, як відомо, там де більше свободи, там і більше ризиків «а чи зрозуміло все написано і структуровано?».
- Глибше розуміння роботи з Vue.
Я ніде не зустрічав такого формулювання плюса Composition API. У мене особисто склалось враження, що він відчувається «ближче» до ванільного JavaScript, і має менше Vue-обгортання між тим, що ми пишемо, і тим що, попадає в бандл. Або принаймні це виглядає явно: наприклад, ми самі маємо імпортувати ref
, щоб оголосити якусь змінну реактивною, замість простого «щоб змінна була реактивною, треба написати її у data
».
На мою думку, це допомагає краще розуміти, що ти робиш, і зменшує відстань від «я знаю Vue» до «я знаю JavaScript».
- Ковток свіжого повітря.
Виключно власне враження: після чотирьох років роботи з Options API можливість писати на Composition API відчувається як ковток свіжого повітря, що стимулює цікавість до чогось нового. А через це просто-таки стає цікавіше писати та створювати щось нове.
- TypeScript.
Ми використовуємо JavaScript, тому тут я просто довірюсь документації Vue, яка каже, що Composition API дружить з типізаціями набагато краще, ніж Options API.
Але, було б неправильно не розповісти й про підводні камені Composition API.
- Складність.
На мою думку, компонент на Composition API складніший для написання. Треба звикнути до певних нюансів роботи з таким стилем, і кілька разів добре побігати по граблях, щоби писати «складні» компоненти.
- Поєднання Options і Composition API.
Ми тут говоримо про міграцію, тож я зроблю припущення, що у вас вже є ціла купа компонентів, написаних на Options API (це не страшно), та велика кількість міксинів до них (а ось це вже страшно).
Міксини доволі важко поєднати з composables в одному компоненті: треба або двічі імпортувати одне і те саме через недоступність компонента this
(Options API) у функції setup
(Composition API), як-от, скажімо, мапити Vuex. Або треба видумувати якісь обхідні шляхи.
Нам доводилось якісь компоненти просто не чіпати, бо вони на міксинах, або для простої дії мапити, наприклад, роутер та стор окремо.
Нові можливості Vue 3
Також можна згадати інші нові фічі Vue 3, які, хоча й зовсім не виділяються на фоні Composition API, проте, теж є доволі значними.
З найприємнішого я б виділив:
- Fragments. Нарешті не потрібно обгортати розмітку компонента, яка має кілька root-елементів, у зайвий div! (якщо він справді зайвий, звісно);
- Emit declaration. Тепер можна прозоро оголошувати еміти компонента, схоже на опис пропсів;
- provide/inject. Замість кастомних глобальних Vue-змінних тепер можна це робити у певному скоупі та явно(!);
- краща підтримка TypeScript. Vue 3 повністю написаний на TypeScript. На скільки я розумію, це класне покращення для TypeScript-проєктів — але ми використовуємо JavaScript, тож тут поділитись власним досвідом я не зможу.
Підтримка актуального стека технологій
Сюди можна внести багато речей, починаючи з Vue 2 End of Life до застарівання кодової бази, та навіть developer experience. На мою думку, якщо проєкт «живе» і розвивається, а не доживає і знаходиться на підтримці — підтримка свіжості стека технологій є необхідною і важливою частиною розвитку.
Додам, що застарівання самого фреймворку — це пів біди. Нові проблеми починаються тоді, коли ти намагаєшся знайти свіжі та підтримувані бібліотеки, які працюють зі старою версією фреймворка. Деяких «вічних» бібліотек це, звісно, не стосується, але як тільки ви почнете шукати щось специфічне: скажімо, селект, календарик або карусельку — мій нещодавній досвід шукати щось для на Vue 2 — не з приємних :)
Як мотивувати необхідність міграції для не-розробника
Ви скажете: а як мотивувати моєму менеджеру або замовнику необхідність міграції? Я вам скажу: на мою думку, у продукті, який розвивається і планує бути актуальним ще довго, залишатись на технологіях, що застарівають, є технічним боргом.
Немає конкретної причини, чому міграцію треба проводити терміново (принаймні, я її не бачу) — особливо зважаючи на час та ресурси, витрачені на неї (особисто у мене, з compat-білдом, пішло на це близько місяця — а деякі баги, спричинені переходом, ми ловили ще майже рік).
Але, застарілий стек технологій в якийсь момент стане для вас токсичним: ви будете обмежені у використанні нових бібліотек, оновленнях (зокрема Security-патчах), а ваш проєкт перестане бути привабливим, і за деякий час перетвориться у те, з чим просто не буде бажання працювати (звісно, тут один крок до ширшої теми про технічний борг та потребу в рефакторингах протягом життя проєкту, хоча й наразі не про це).
Також одразу додам! Ми говоримо про активні проєкти, які розвиваються. Якщо продукт вже на стадії підтримки — це інша ситуація, і, я сумніваюсь, що в такому разі міграція є необхідною.
Час на міграцію
У нашій команді це робив я, і міграція дев’яти застосунків до рівня «запустилося і не видає багів на кожному другому кроці» на compatibility-білді зайняло близько місяця (сюди ж я вкладаю і міграцію на Vue Test Utils v2, і виправлення unit-тестів).
Втім, варто зауважити, що деякі баги, спричинені міграцією, ми все ж таки періодично відловлювали понад рік.
По моїх відчуттях, з першим застосунком йшло доволі туго, але потім ви зрозумієте патерн, за яким треба робити зміни, і далі справа вже піде «механічно».
Проте, ви самі прекрасно знаєте це слово: «залежить» :)
Залежить від розміру проєкту, від його застарілості, від кількості часу і ресурсів на це. Можливо, у вас це вийде набагато швидше, та можливо і довше. А тепер до роботи!
Як мігрувати
Отже, ви вирішили мігрувати! Але як це зробити?
Зробити основну частину роботи вам допоможе офіційна документація Vue. Тут я наведу лише чекліст, про який не варто забувати під час основної частини міграції.
А речей-то насправді небагато:
- Оновити пакети.
- Оновити використання Vue-бібліотек (Vue, Vue Router, Vuex, Vue-i18n, наприклад), з, як правило,
new …()
наcreate…()
. - Оновити конфігурацію бандлера, та, за потреби, додати compatibility build, щоб не переписувати і тестувати всі breaking changes (а потреба, я думаю, буде — ми ж все ж мігруємо, а не починаємо з нуля).
- А далі просто запускаєте проєкт і поштучно виправляєте помилки, які викидає вам консоль — звучить найпростіше, але, боюсь, сподобається вам в цьому процесі найменше :)
Фінал
Отже, вітаю вас! Ви виконали основні кроки, ваш проєкт запустився і навіть не валиться. Проте, скоріш за все, все одно будуть проблеми. Неочевидні та специфічні. Саме такі ми відловлювали потім понад рік, а над деякими я сидів по кілька днів. Рука так і тягнулась то до лоба, то до сигарети :)
Саме про ці специфічні та неочевидні кейси, з якими ми стикнулися, я розповім у другій статті. Сподіваюсь, ця стаття була вам корисною та підштовхнула, або навіть надихнула вас на міграцію — якщо раптом ви цього ще не зробили!
А тепер щось середнє між TLDR; та FAQ
Q: Довго мігрували?
A: Близько місяця мого фултайм-ресурсу разом з Vue Test Utils v2 і виправленням тестів.
Q: А compatibility build використовували?
A: Звісно! Без нього це було б набагато довше.
Q: Як враження?
A: Рік пройшов, політ нормальний! Враження позитивні, а про міграцію не шкодуємо.
Q: Чому це треба мені як розробнику?
A: Composition API та розв’язання проблем міксинів у великих проєктах, а також актуалізація технічного стека, а отже і доступ до нових версій бібліотек та оновлень.
Q: Чому це треба власнику, менеджеру?
A: Якщо це «живий» проєкт що розвивається, то, на мою думку, застарілі технології є технічним боргом, який з часом стане токсичним і звʼязуватиме вам рухи з пошуком бібліотек, нових рішень, та розв’язання проблем. А отже сповільнить швидкість розробки та якісь результати.
Q: Чи були проблеми після міграції?
A: Були, але небагато. Втім, ці кейси були дуже специфічними за моїми відчуттями, тому детальніше я розповім про них у наступній статті.
Q: А Vue 2 хіба вже старий?
A: Не смертельно, але є таке: того року був End of life, а оновлення тулзів і бібліотек — вже, як правило, на Vue 3.
Q: Ми мігрували, ура! Чи треба переписувати компоненти з Options API на Composition API?
A: На мою думку, тільки якщо є потреба. Наприклад, потреба розгрести пекло міксинів.
Q: Composition API vs Options API?
A: Я б казав (а я це піддивився в офіційний Vue документації) Options API — для невеликих проєктів. Composition API — для середніх і більших.
Q: Міксини vs composable функції?
A: Міксини — все. У Vue 3 вони лише для сумісності. Рекомендований спосіб — composables.
12 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів