Как мигрировать с AngularJS на Vue используя ngVue
Перевод. Оригинал статьи - https://medium.com/dailyjs/how-to-migrate-from-angularjs-to-vue-4a1e9721bea8
Наше фронтенд-приложение называется Dawex(маркетплейс для покупки и продажи данных) - это SPA(single-page application), написанное на AngularJS. Первые строчки кода были написаны летом 2015 года. Оглядываясь назад, это было абсолютно правильноe решение в тот период. У команды был большой опыт работы с ним, и он отлично подходил под наши требования для платформы. Angular (новый) был только в альфа-версии. React только начал набирать популярность и использовался в основном среди фронтенд-сообщества , но у нас не было достаточного опыта работы с ним. А Vue … ну, его еще не было.
Кто знал что Vue будет среди основных игроков?
Хотя наше приложение разработано на старом фреймворке(AngularJS был написан в 2009 году), мы построили полноценную архитектуру, которая масштабировалась чертовски хорошо! С самого начала, мы всегда старались быть на переднем крае того, что лучше для платформы и для наших пользователей. Также мы не забывали об удобстве разработки. Мы используем компонентный подход с современным Javascript(ES2015+) и продвинутыми тулзами, такими как Babel, ESLint, Gulp, Jest, Redux, Webpack, и другими замечательными технологиями, которые предлагает нам open-source.
Ну и что?
Как фронтенд-разработчику, мне нравится каждый новый красивый фреймворк или новая тулза. (конечно же, это не значит что он окажется у нас в стеке). Как вы могли уже догадаться, Vue привлек мой интерес настолько, что я захотел начать мигрировать наше приложение с AngularJS на Vue. API Vue намного проще. Это впечатляет, насколько быстро вы можете начать с ним работать. Например, вам нужен только один файл(.vue) чтобы создать компонент, и все, он готов к использованию! Иногда, мне до сих пор сложно с camelCase/kebab-case спецификацией для объявления компонента и его использованием в HTML в AngularJS . Мы, по правде, не страдали от проблем с производительностью, но если начистоту, dirty checking(проверка на «грязные» свойства объекта в AngularJS) - это НЕТ. Система реактивности в Vue же - ненавязчива и используется в сочетании с легковесной реализацией Virtual-DOM, что позволяет отслеживать изменения очень быстро Также, опыт разработки гораздо приятнее. Я обнаружил, что я намного более удовлетворен и мотивирован, когда разрабатываю на Vue. Больше не буду рассказывать дальше про Vue vs AngularJS, на просторах интернета много постов на эту тему. Возвращаясь к миграции. Ее нельзя сделать за один шаг, соответственно это должно быть постепенно и мягко, насколько это возможно Следующая часть статьи посвящена деталям и мыслям насчет получившегося эксперимента
Встречайте, ngVue!
https://github.com/ngVue/ngVue
ngVue - Use Vue2 components in Angular 1.xgithub.com
ngVue - это модуль для AngularJS. Он позволяет безболезненно интегрировать Vue компоненты внутри AngularJS-приложения.
Это означает, что вы можете начать разработку новых фич на Vue, или конвертировать в него уже существующие компоненты
Вот мои слайды по этой теме с LyonJS meetup: http://slides.com/npayot/ng-vue
Этот модуль предлагает директиву vue-component и фабрику createVueComponent
Директива дает возможность включить Vue компонент с указанными свойствами. Фабрика дает тот же результат, создавая директиву в AngularJS, которая привязана к определенному Vue компоненту
<template>
<div>Hello !</div>
</template>
<script>
export default {
props: {
firstName: String,
lastName: String
}
}
</script>
Вот AngularJS компонент:
export const App = {
template: `
<vue-component
name="Hello" vprops="$ctrl.person">
</vue-component>
`,
controller() {
this.person = { firstName: 'John', lastName: 'Doe' };
}
};
Как видите, директива vue-component
принимает два параметра - name
и vprops
.
name
- это название Vue компонента, зарегистрированного через value в AngularJS модуле. vue-component через nameполучает вlink название Vue компонента, экземляр которого он получает с помошью сервиса$injector . Таким образом, он может быть инстанцирован и отрендерен с помощью тэга <vue-component>
. Помимо этого надо не забыть включить ngVue в главный модуль AngularJS.
import angular from 'angular';
import ngVue from 'ngVue';
import App from './App'; // AngularJS component
import Hello from './Hello.vue'; // Vue component
angular
.module('ngVueApp', ['ngVue'])
.component('app', App)
.value('Hello', Hello);
vprops позволяет передавать данные из контекста AngularJS в компонент Vue. Его также можно использовать следующим образом, чтобы дать более точный контроль над свойствами компонента:
<vue-component
name="Hello"
vprops-first-name="$ctrl.person.firstName"
vprops-last-name="$ctrl.person.lastName">
</vue-component>
createVueComponent
Эта фабрика интересна тем, что позволяет делать биндинг Vue-компонент на директивы AngularJS. Это позволяет не использовать vue-component, не регистрировать Vue через value, а использовать свой собственный тэг:
<hello
vprops-first-name="$ctrl.person.firstName"
vprops-last-name="$ctrl.person.lastName">
</hello>
import angular from 'angular';
import Vue from 'vue';
import ngVue from 'ngVue';
import App from './App'; // AngularJS component
import Hello from './Hello.vue'; // Vue component
angular
.module('ngVueApp', ['ngVue'])
.component('app', App)
.directive('hello', createVueComponent =>
createVueComponent(Vue.component('Hello' Hello)));
Но интеграция Vue компонентов - это только первый шаг на пути к окончательной миграции. К сожалению (в этом конкретном случае…), AngularJS идет с достаточно крупным слоем, который мы не можем использовать внутри Vue: Dependency Injection(внедрение зависимостей). Если Вы долго разрабатывали на AngularJS, наверняка, у вас накопилась куча сладеньких сервисов\фабрик\провайдеров. И было бы жестоко не иметь возможности использовать их внутри Vue, не правда ли? Как минимум на период совместного существования AngularJS и Vue в проекте. Кстати есть замечательное решение для этого..
Использование сервисов AngularJS в Vue компонентах
Благодаря модулям ES2015 , сервисы AngularJS могут быть экспортированы и импортированы. Без dependency injection! Чтобы этот механизм заработал, инстансы сервисов должны быть привязаны к контексту выполнения AngularJS. $injector нам в помощь! Вот как это работает:
import angular from 'angular';
import { HelloService } from './hello.service';
angular
.module('App', [])
.service('HelloService', HelloService);
import angular from 'angular';
export class HelloService { ... }
export let helloService;
angular
.module('App')
.run($injector => {
helloService = $injector.get('HelloService');
});
Теперь мы можем импортировать и использовать helloService везде:
import {helloService} from 'path/to/hello.service'
Тадам! 🎉🎉🎉
Заключение
Я думаю, использование ngVue и избавление от dependency injection(ну как избавление….типа того…) для сервисов AngularJS - это хороший подход для постепенного перехода на Vue Очевидно, в нем ей свои ограничения, и наверняка еще будут всякие интересные вещи, которые еще предстоит узнать, что будет поводом для еще одного поста 🙂