As I write this article, we have just removed the last line of AngularJS code from our application code base, completing a four-month non-invasive effort to migrate our application from AngularJS to VueJS. In this article, I will share our experiences along the way.

Some background

Our application (Holistics. IO) is an SQL-based business intelligence (BI) platform written in Rails, Sidekiq, PostgreSQL, and AngularJS. Our Rails application started in late 2013 as a simple application that uses jQuery and AngularJS. The main features/functions we use with AngularJS are as follows:

  • View model bindings (Controller, View + template engine)

  • Dependency injection (service, factory, directive)

  • Angular third-party components (UIB-Modal, UI-Select,…)

The rest is internal custom JavaScript.

Other Translations (1)

Problems we have with Angular

As we upgraded our app, we encountered some issues when using AngularJS:

  • Rendering performance: As a data tool, due to the nature of AngularJs, we have to spend a lot of time rendering a large data table.

  • Angular documentation is not very good: until this becomes a problem, nothing else is. The deeper we get into AngularJS, the harder it is to understand its documentation.

  • Two-way data flow makes logic difficult to handle, whether writing components or view controllers. This is probably the single most important reason why AngularJS is bad to use.

Consider different frameworks

Before deciding, let’s take a closer look at the options:

Angular 2

We did spend some time exploring Angular 2. Angular 2 is even harder for us to understand than Angular 1. It brought a lot of new TypeScript changes, new template syntax, and so on, but we felt that it didn’t really address our core issues. In addition, the path from V1 to V2 has been puzzling us since then.

ReactJS

We took a close look at ReactJS. As much as we loved its philosophy and ecosystem, one thing surprised us: we couldn’t find a clear, clean, incremental migration path that would prevent us from supporting new features in 3-4 months.

AngularJS uses an HTML-based template system, while ReactJS uses JSX. We couldn’t find a way to get the two technologies to coexist nicely in the migration process.

For a secondary subjective reason, I find JSX more verbose than HTML-based templates.

EmberJS

EmberJS is not a JS library, but a Web application framework, and we had to rewrite everything based on EmberJS.

Why did we choose VueJS: Gradual migration

All things considered, we chose VueJS, but the most important deciding factor for us was that we saw a clear and gradual migration path to VueJS without disrupting the development path. In fact, I’m willing to bet that our customers didn’t notice any significant changes during the migration. They didn’t know which pages they visited were implemented by Angular and which were implemented by VueJS.

Vue uses similar techniques to ReactJS, component-based, attribute downlink event uplink, and so on. It bears a striking resemblance to AngularJS in terms of template engines. It’s like a nice mix of AngularJS and ReactJS. This made us feel perfect because we had a lot of AngularJS templates and our main problem was the complex logic that Angular components brought with them.

In fact, most of the time all we need to do is change the ng- to v- in the code, which is fantastic!

As we went along, we felt more and more that we had made the right choice, that it solved some of our early problems: good performance, single-file components, clean code structure, slots, etc.

Also, during the migration, because of the way Vue was structured (one-way data flow, component-based), it forced us to rethink and refactor the code rather than continue to write rotten code, which simplified our code logic.

One last point I would like to make is that I found VueJS documentation to be very well written and very clearly structured. This is another main reason why we chose VueJS. When I first used Vue, I spent 30 minutes reading its documentation and immediately felt compelled to try this thing out.

How do we move gradually:

Here are our simple steps for migrating (note that some of these things are relevant to the Rails application environment we’re running in and may be different if you’re not using Rails) :

Convert AngularJS controller logic to VueJS

In a step-by-step migration strategy, we want to make as few changes as possible when introducing VueJS. So we started with standard AngularJS and template files and introduced VueJS:

// user_edit_controller.js.es6`
import Vue from 'vue'

app.controller('UserEditCtrl', ['$scope', '$http', 'Ajax', 'Util', 'Modals',  
  function ($scope, $http, Ajax, Util, Modals) {
    let vapp = new Vue({
      el: '#v-wrapper',
      components: {
          ...
      },
      data: {
      }
    });
  }
]);Copy the code

<! -- `users/edit.html.erb` --> <div ng-controller="UserEditCtrl"> <div id="v-wrapper"> <! -- vuejs logic goes here... --> <input v-model="username" placeholder="Username" /> ... </div> </div>Copy the code

We introduced Vue logic into the application without changing the front-end structure of any related application. This greatly reduces the risk of errors during migration, and we can quickly convert a small fraction of AngularJS implementations to VueJS implementations in 1-2 hours, then test and deploy them without worrying that it will cause regression defects.

2. Convert AngularJS services to ES6 modules

We first need to find an alternative to the $HTTP service that is heavily used in AngularJS. We just used Axios. We no longer use $HTTP directly, but we wrap it around abstractions to make changes very simple.

Then, we define a lot of AngularJS like this:

// users.js
app.service('Users', ['$http', 'Ajax',  
  function ($http, Ajax) {
    this.create = function(user) {
      // ...
    }
  }
]);Copy the code

Use ES6 class syntax instead:

// users.js.es6 export default class Users { static create(user) { // ... }}Copy the code

If Angular code uses these services in other controllers, we copy them and implement them using ES6 class syntax, keeping the original Angular version until no more Angular code uses them. This can make the code repeat in a short time, but we just need to be careful and put extra comments in the code to link the two versions.

3. Use VueJS components instead of AngularJS controllers

With the above two points in place, some AngularJS controllers can be fully migrated to VueJS. Similar to step 2 above, we use ES6 syntax instead of app.controller() definition. This time, however, we use Vue’s single-file component:

File: user_edit. Vue

<template> <div> <! -- vuejs logic goes here... --> <input v-model="username" placeholder="Username" /> ... </div> </template> <script> import Users from 'users.js.es6' export default { data: { }, methods: { }, mounted() { // initializing } }; </script>Copy the code

4. Add installation entry for Rails controller/view

By default, every Rails page loads with a rendered view. In the Vue single-file component above, we changed the Raisl view, the users/edit.html.erb file, to:

<div class="v-user-edit">  
  <user-edit></user-edit>
</div>Copy the code

Then add some code to install the page as the correct Vue component when it loads:

import UserEdit from 'user_edit.vue'  
let vueConfig = {  
  el: '.v-user-edit',
  components: {
    UserEdit
  }
};
new Vue(vueConfig);Copy the code

In effect, the above code is abstracted into reusable functions that can be called in different pages.

conclusion

We completed the migration of the framework at the end of September 2017, after about four months of non-invasive work (we will continue to add new features as we move). We don’t actually make migration the most urgent task, and whenever we make changes that involve old Angular code, we convert it to a Vue implementation before making changes.

After the migration, we harvested:

  • Very clean code and modules (component-based), as well as VueX and Vue Store; They greatly improve programming efficiency

  • No more complicated logic

  • Improved UI performance

This is not to say that Vue is the best, it just works well in our particular situation: Angular’s inherent design nature makes implementing apps with Angular a heavy load, and Vue fills that void nicely for us, all of which is implemented naturally and progressively.

What do you think? Share them with us in the comments below. Hope to learn more about your situation!