Перевод: Vue.js: How to Migrate a large project from Vue 2 to Vue 3
Команда Vue.js выпустила Vue 3.0 в сентябре 2020 года. Эта новая версия содержит множество новых функций и оптимизаций, но также имеет несколько критических изменений.
В июне 2021 года команда Vue.js выпустила версию Vue 3.1. Этот новый релиз поставляется с @vue/compat
(он же «сборка миграции»). Он позволяет плавно переносить большие проекты, запуская кодовую базу Vue 2 вместе с изменениями Vue 3.
Переход на Vue 3 может быть сложной задачей (в зависимости от размера вашего проекта). В Crisp мы недавно перенесли наше приложение (250 тыс. строк кода) с Vue 2.6 на Vue 3.2 примерно за 2 недели.
Мы подготовились к миграции, прочитав официальное руководство по миграции Vue (Vue Migration Tutorial), но при миграции нашего проекта столкнулись со множеством различных проблем. В этой статье я опишу наш опыт миграции:
Первоначальная философия Vue.js, созданного в 2013 году, заключалась в создании минималистичной альтернативы AngularJS 1 .
В то время Angular представлял собой громоздкий фреймворк с массой новых функций. Первые версии Vue.js были похожи на мини-фреймворк с шаблонами, привязкой данных (Data Binding), фильтрами (Filters) и директивами (Directives).
Затем в 2016 году был выпущен Vue 2 (почти одновременно с Angular 2) и стал отличной альтернативой AngularJS. Фактически, многие разработчики, использующие Angular 1, решили перейти на Vue 2, потому что им не нравился Angular 2. Vue 2 предлагал что-то столь же простое, как AngularJS, но с более высокой производительностью.
Vue 3 так же создавался с расчетом на производительность. Это скорее эволюция, чем революция. Большинство новых функций и критических изменений были выпущены из соображений производительности.
Внутренняя система реактивности была переработана с нуля, и по этой причине поддержка IE 11 была прекращена (что не является большой потерей 😂 ).
Наконец, эта новая версия должна быть более модульной и включает такие функции, как Composition API .
Глобальный Vue API устарел. Хотя он все еще поддерживается с помощью @vue/compat
, потребуется переработать ваше приложение, чтобы полностью поддерживать Vue 3.
Это означает, что невозможно будет использовать API, такие как Vue.set или Vue.delete. Поскольку Vue 3 поставляется с новой системой реактивности, использование этих API становится бесполезным.
Вместо использования Vue.set(object, key, value)
вам придется напрямую использовать object[key] = value
. То же самое и с Vue.delete(object, key)
, который можно заменить на delete object[key]
.
Как объяснялось ранее, Vue.js был создан как альтернатива Angular 1. Именно поэтому изначально поддерживались фильтры.
Самая большая проблема с фильтрами — это производительность: функция фильтрации должна выполняться каждый раз, когда данные обновляются. По этой причине поддержка фильтров в Vue 3 была прекращена.
Это означает, что нельзя будет использовать такие вещи, как {{ user.lastName | uppercase }}
в шаблонах Vue 3.
Вместо этого вам придется использовать вычисляемые свойства, такие как {{ uppercasedLastName }}
, или методы, такие как {{uppercase(lastName)}}
.
Начиная с Vue 3, ваше приложение и плагины больше не создаются глобально. Это означает, что в одном проекте может быть несколько приложений Vue.
Пример на Vue 2:
import Vue from "vue"; new Vue({ router, render: h => h(App) }).$mount("#app");
Пример на Vue 3:
import { createApp, h } from "vue"; const app = createApp({ render: () => h(App) }); app.use(router); app.mount("#app");
Использование условий v-if со списками v-for было возможно в Vue 2. Из соображений производительности это поведение было отключено во Vue 3.
Начиная с Vue 3, вам нужно будет использовать свойства вычисляемого списка.
API v-model немного изменилось во Vue 3.
Свойства value
переименовано в modelValue
.
<ChildComponent v-model="pageTitle" />
ChildComponent нужно переписать так:
props: { modelValue: String // previously was `value: String` }, emits: ['update:modelValue'], methods: { changePageTitle(title) { this.$emit('update:modelValue', title) } }
Замечательно то, что теперь можно иметь несколько пользовательских значений v-model , например v-model:valueA
, v-model:valueB
и т. д.
В Vue 2 можно было использовать экземпляр Vue для создания глобальной EventBus с vm.$on
и vm.$off
. Начиная с Vue 3, это больше невозможно, поскольку vm.$on
и vm.$off
были удалены из экземпляра Vue.
В качестве замены предлагаем использовать библиотеку Mitt:
mounted() { this.eventbus = mitt(); eventbus.on("ready", () = { console.log("Event received"); }); eventbus.emit("ready"); }
тот же код, использующий Vue 2, будет:
mounted() { this.$on("ready", () = { console.log("Event received"); }); this.$emit("ready"); }
По-прежнему можно отправлять события от компонентов к их родителям, однако все события должны быть объявлены с помощью новой опции emit
(она очень похожа на существующую опцию props
).
Например, если у вашего компонента есть свойство @click
, генерируемое с помощью this.$emit("click")
, вам нужно будет объявить событие » click
» в вашем компоненте:
props: { name: { type: String, default: "" }, }, emits: ["click"], // events have to be declared here data() { return { value: "" } }
Наше приложение называется Crisp. Это приложение для обмена сообщениями для крупного бизнеса, которым ежедневно пользуются 300 тысяч компаний по всему миру. Компании используют Crisp, чтобы отвечать своим клиентам, используя командную папку «Входящие», которая централизует чат, электронную почту и многие другие каналы.
Поскольку наше текущее приложение используется многими разными пользователями, для нас, очевидно, важно ничего не сломать. Таким образом, нам также нужно было ежедневно улучшать наше программное обеспечение, чтобы мы могли исправлять ошибки и новые функции.
Итак, нам нужно было иметь две разные ветки:
Кроме того, мы каждый день выпускали бета-версию нашей кодовой базы Vue 3 и вносили почти ежедневные изменения.
Наконец, мы решили не полагаться на новые API Vue, такие как Composition API , и перенести только то, что необходимо. Причина этого заключалась в том, чтобы снизить риск введения регрессий.
Наше приложение использует Vue Cli ( webpack ). Опять же, мы решили пока не переходить на Vite , чтобы не допустить появления новых проблем, поскольку наша система сборки довольно сложна.
Перенести Vue Cli на поддержку Vue 3 довольно просто.
Сначала вам нужно отредактировать файл package.json, чтобы обновить Vue.js и его зависимости.
Поэтому мы заменяем "vue": "^2.6.12"
на "vue": "^3.2.6"
.
Кроме того, нам придется использовать "@vue/compat": "^3.2.6"
, что позволит плавно перенести кодовую базу с Vue 2 на Vue 3.
Нам также придется обновить "vue-template-compiler": "^2.6.12"
до "@vue/compiler-sfc": "^3.2.6"
.
Теперь нам нужно обновить наш файл vue.config.js и отредактировать функцию chainWebpack. Это заставит все ваши существующие библиотеки использовать пакет @vue/compat
.
// Vue 2 > Vue 3 compatibility mode config.resolve.alias.set("vue", "@vue/compat"); config.module .rule("vue") .use("vue-loader") .loader("vue-loader") .tap(options => { // Vue 2 > Vue 3 compatibility mode return { ...options, compilerOptions: { compatConfig: { // default everything to Vue 2 behavior MODE: 2 } } }; });
Теперь нам нужно создать экземпляр Vue следующим образом:
import { createApp, h, configureCompat } from "vue"; const app = createApp({ render: () => h(App) }); app.use(router); app.use(store); // Initiate other plugins here configureCompat({ // default everything to Vue 2 behavior MODE: 2 }); app.mount("#app");
Нам нужно будет использовать последнюю версию Vue Router "vue-router": "4.0.11"
Использование последнего Vue.js Router не сильно отличается. Основное отличие состоит в том, что вам придется вручную включить режим истории, используя:
import { createWebHistory, createRouter } from "vue-router"; var router = createRouter({ history: createWebHistory(), routes: [ // all your routes ] });
Наше существующее приложение во многом зависит от фильтров (около 200 использований). Первым делом нужно было выяснить, сколько фильтров мы использовали. Поскольку современные IDE (VSCode, SublimeText) поддерживают поиск Regex, мы создали регулярное выражение, чтобы мы могли узнать все использования фильтров Vue в наших шаблонах: {{ (.*?)\|(.*?) }}
Так как Vue 3 полностью отказывается от поддержки фильтров, мы попытались найти элегантный способ по-прежнему использовать фильтры. Решение заключалось в переносе фильтров Vue на настраиваемые Singletons Helpers. .
Например, на Vue 2:
Vue.filter("uppercase", function(string) { return string.toUpperCase(); });
Становится на Vue 3:
uppercase(string) { return string.toUpperCase(); } export { uppercase };
Затем мы глобально создали экземпляр класса StringsFilter:
import { uppercase } from "@/filters/strings"; app.config.globalProperties.$filters = { uppercase: uppercase };
Наконец, мы можем использовать наш фильтр:
{{ firstName | uppercase }}
становиться {{ $filters.uppercase(firstName) }}
По мере продвижения процесса миграции вы будете замечать ошибки в консоли браузера. В режиме совместимости с Vue 3 предусмотрены различные журналы, которые помогут вам перенести приложение на Vue 3.
Вместо того, чтобы пытаться перенести функцию за функции или шаблон за шаблоном, мы рекомендуем начать перенос с API.
Например, если вы видите в журналах уведомление об устаревании WATCH_ARRAY, мы рекомендуем ознакомиться с руководством по миграции (migration guide), указанным в логах.
Затем выполните поэтапную миграцию каждого массива watch.
После завершения миграции всех watch вы можете отключить режим совместимости для этой функции:
import { createApp, h, configureCompat } from "vue"; const app = createApp({ render: () => h(App) }); // Initiate all plugins here configureCompat({ // default everything to Vue 2 behavior MODE: 2, // opt-in to Vue 3 behavior for non-compiler features WATCH_ARRAY: false }); app.mount("#app");
Vue 3 поставляется с пакетом @vue/compat
, поддерживающим библиотеки Vue 2 и Vue 3. Однако режим @vue/compat
также снижает производительность.
Использование режима совместимости возможно только при преобразовании вашего приложения в Vue 3 и все его библиотеки. После того, как весь проект и библиотеки будут мигрированы, вы можете избавиться от режима совместимости.
Чтобы этого добиться, нам придется перенести все библиотеки на совместимые с Vue 3.
Все официальные библиотеки Vue (Vuex, Vue Router) были перенесены на Vue 3, в то время как большинство популярных пакетов уже имеют версии, совместимые с Vue 3.
Около 20% используемых нами библиотек не имеют версии Vue 3, поэтому мы решили форкнуть все библиотеки, которые еще не были перенесены на Vue 3, например vue-router-prefetch .
Перенос библиотеки написанной на Vue 3 обычно довольно прост и занимает от 30 минут до полдня, в зависимости от сложности библиотеки.
После того, как мы закончили миграцию библиотеки для поддержки Vue 3, мы создаем « pull request » в исходную библиотеку, чтобы другие могли извлечь выгоду из нашей работы.
Vue 3 имеет множество различных улучшений производительности благодаря новой внутренней системе реактивности. Размер Javascript heap был уменьшен с 20-30% в большинстве случаев и с 50% для некоторых сложных списков. В нашем случае использования обмена сообщениями мы заметили значительные улучшения ЦП.
Наше новое приложение Crisp стало работать намного быстрее.
Пока мы писали эту статью, мы занимались развертываем нового приложение Crisp в производственной среде. На перенос нашего приложения у нас ушло около 2 недель.
Для сравнения, переход с Angular 1 на Vue 2 занял у нас около 9 месяцев.
Переход с Vue 2 на Vue 3 — важная, но не невыполнимая задача. Эта новая версия Vue предлагает несколько отличных улучшений производительности.
Чтобы поблагодарить сообщество Vue.js, мы начали вносить свой вклад в проект в качестве золотого спонсора. Как компания, мы чувствуем, что должны расширить возможности проектов с открытым исходным кодом, чтобы построить лучший мир, в котором программное обеспечение и среда могут взаимодействовать друг с другом.
Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…
Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…
Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…
Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…
View Comments
"Перенос библиотеки Vue 3 обычно довольно прост и занимает от 30 минут до полдня, в зависимости от сложности библиотеки."
что это значит? вы переписывали код сторонней библиотеки?