Перевод. Оригинал статьи - 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 Очевидно, в нем ей свои ограничения, и наверняка еще будут всякие интересные вещи, которые еще предстоит узнать, что будет поводом для еще одного поста 🙂