Vue.js – The Next Library for Angular 1 Developers

Angular is the most successful JavaScript framework ever. I cannot back this up with any numbers, but based on my experience as a developer over the past few years, it is everywhere. It is truly a complete framework, and it’s no wonder why it has achieved so much success in the industry. However, like all technology, it is quickly becoming dated, and new options have entered the fold.

Libraries like React and Angular 2+ have learned from their predecessors and employ strategies and optimizations that result in less code bloat and better performance.  These new-age frameworks also leverage bleeding edge development tools such as Webpack and Babel, which allow developers to utilize future standards (and non-standards) of the JavaScript language, resulting in increased productivity and cleaner code.

But with all tools and technologies, there is a learning curve to climb and risk involved when introducing new tools into an existing development environment.  Angular 1 is a known entity and, from the perspective of a developer who wants to get things done and shipped, there’s little reason to try newer libraries. However, there is a library that feels like that happy medium between Angular 1 and new age libraries.

In this blog post, I’d like to present Vue.js as the alternative to the more popular new age libraries and frameworks and one which Angular 1 developers should be able to pick up quickly.  By comparing Vue to newer frameworks, providing an overview of benefits of the library and showing examples of how Vue can integrate into an existing Angular codebase, I’m hoping that I can convince you that the next step in your JavaScript framework evolution should be towards Vue.

Comparison to Other Frameworks

While there are a number of JavaScript frameworks that one can choose from (and new ones coming out on a seemingly daily basis) I’d like to focus on the more popular options of React and Angular 2+ for a couple of reasons:

  • Both are at the forefront of developers’ minds when considering client side frameworks
  • They’re backed by major corporations
  • Many view these two frameworks as the de facto next generation frameworks that they should adopt

While these two technologies are immensely popular, they are not without their pitfalls.

React

Steep Learning Curve

Building a React app requires adopting a different mindset compared to the structure of a traditional MVC/MVVM application that one would build with Angular 1. Couple that with the introduction of component lifecycle hooks, the complete abstraction of the DOM and the “data down, actions up” paradigm, getting a grasp on how to design a React app can take days if not weeks.

Markup in JavaScript (JSX)

While one can write React apps without using JSX, nearly the entire community favors it due to its concise and declarative nature. Therefore, you will see almost all documentation, blog posts, and Stack Overflow articles written in the syntax. However, many web developers are put off by the idea of mixing markup with JavaScript and might favor separating the two. This is just not possible with React (unless you pull in other libraries) due to its nature as a library where the developer expresses the view entirely in JavaScript.

Tooling Is Necessary to Achieve the Full React Experience

Even if you are 100% on board with JSX, the amount of tooling required to target this and other advanced language features can be staggering.  While modern JavaScript tooling is prominent with the use of new frameworks and libraries, they are practically required to be able to develop with React.

React Is Not Easily Integrable

Related to the above point, due to the necessity of transpilation and build tools to build a React app, one can not simply “drop” the library into an existing app without significantly modifying its build pipeline.

Angular 2+

Still Bleeding Edge

Despite it being released in September of 2016 (and 4.0 being in RC as of March 1st, 2017) Angular 2+ is still a relatively young framework.  As of this writing, it currently has over 1,000 open issues on GitHub, and about 180 issues opened over the past month (GitHub pulse stats can be viewed here).  Google has an entire team to tackle these issues, but these numbers show that there will be bumps in the road for teams that adopt the framework at this stage in its lifecycle.

Huge Size

Based on this analysis, Angular 2+ checks in at around 110Kb minified and gzipped and over 140Kb(!!!) when you include all Rx extensions.  While these numbers surely will improve with future releases and overall app size can be reduced used dead code elimination, these initial numbers point to Angular 2+ being a much larger framework than its counterparts.

Tooling Required (and It’s Complicated)

Similar to the above points regarding tooling for React, build tools and transpilation is required to work with Angular 2+.  Over the past year, while in Beta, RC and after the release, a common complaint has been that the most difficult part of adopting Angular 2+ has been getting the tooling setup and working.

Targeted Use Cases

Angular 2+ is an ambitious project that looks to solve a number of problems one faces when developing a modern web application; server-side rendering, progressive web features, unit testing and type checking (via typescript).  Generally, features like these are required for significantly large applications created and maintained by multiple developers.  However, there are many classes of apps that don’t require all of the bells and whistles that Angular 2+ aims to provide, rendering it overkill in a lot of situations and use cases.

For comparisons to other frameworks not mentioned here, check out Vue’s docs.

What Does Vue Offer?

In my opinion, Vue is what Angular 2+ would have been had the Angular team not decided to completely rewrite the framework.  Its template syntax is nearly identical and creating a Vue component is very similar to the component API introduced in Angular 1.5.  However, Vue offers many of the benefits that newer frameworks have without the headaches.

Modern Framework

Vue supports a complete component lifecycle paradigm (similar to React) along with a focus on using components and composition to build a web application. In addition, the feedback at development time and error messaging are second to none as Vue provides descriptive error messages that provide hints as to why a bug might be occurring.

Small API and Learning Curve

Vue components are self-contained and require little more than declaring and exporting a component object. There is no registration of components with the application or declaring dependencies to be injected by the framework.  They’re just objects.  Using other components is as simple as importing them into your dependent file and registering them with the dependent component. In Vue, it’s components all the way down.

Tooling is Not Required

One facet of Vue that cannot be overlooked is its “0-60” development time speed: how much time is required between pulling down the library and getting a functioning app on the screen. With most modern frameworks, this time can be measured in minutes or even a couple of hours (if you lack experience with tooling). However, with Vue, you can create an index.html, include the Vue dist script in the head, write a component and you’ll be up and running. No tooling is required to use Vue.

Small File Size + Blazing Speed

Based on these measurements of size and speed, Vue outperforms the competition by a wide margin. With today’s focus on improving the user experience on mobile devices, this advantage cannot be overstated.

Integrating with an Angular 1 App

Angular 1 is a great all-purpose framework for building an advanced web application. However, it is starting to show it’s age:

Performance

Due to its change detection system, Angular 1 web apps tend to slow down as more data bindings and interactions are included on a page. There are ways to mitigate these performance issues but they require in-depth knowledge of the framework and even so, certain classes of performance issues cannot be avoided.

Error Messaging

In my opinion, this is Angular 1’s biggest drawback in comparison to newer libraries. Angular 1 often fails silently when it comes to template bindings and expressions. And when there are errors, they are generally not useful and simply link to a generic error description in the Angular docs

Lots of Boilerplate

Browsers and front-end tooling are in a much better place than it was when Angular 1 was first released. As such, Angular 1’s API of registering and injecting components feels very heavy-handed and requires a good deal of boilerplate.

Vue can help mitigate these issues and introducing it into an existing codebase can allow for a developer to achieve higher productivity while reducing the potential for bugs due to writing less code.

Demo Application

To show this ease of integration, let’s look at a demo app that strives to integrate Vue into an existing Angular 1 application. Please note that the approaches listed below are only for situations where you are unable to create a feature or page entirely in Vue. It is desirable to not mix competing client code libraries with each other, but there are situations in codebases where this is simply not possible, and exceptions need to be made.

Code for the demo app can be found here. The app is a simple reddit-reader app where you can select a subreddit from a drop-down to view posts and select a specific post to view its details.

This app has the following characteristics:

  • Angular 1.6 application that utilizes Angular’s component API to build out the app structure
  • Uses require.js for module definition and async script loading in the browser
  • text plugin is used for async loading of templates. This bypasses Angular’s $template service, and all directive and component templates are available at time of registration
  • All vendor scripts are requested from Cloudflare CDN (i.e. no local scripts)

This application employs two strategies in integrating Vue with an existing Angular 1 application.

Mounting Vue Component via an Angular Directive

For simple data passing between Angular and Vue, we can mount a Vue component onto a DOM element that is controlled by an Angular directive:

  • In the link function of an Angular directive, mount a Vue instance on the managed DOM element
  • Using $scope service, in a $scope.$watch callback, you can set properties on the Vue instance. Vue’s change detection will pick up on these changes and update the UI accordingly
  • Angular service and component methods can be called by a Vue component instance’s method. These methods can then be passed down to child Vue components.
function directive(redditService, $state) {
 return {
    restrict: 'E',
    scope: {
       results: '=',
       subreddit: '='
    },
    link: function($scope, elem, attrs) {
       var vueInstance = new Vue({
//set the underlying DOM node managed by Angular directive as the mount
//DOM node for root Vue component
          el: elem[0],
          data: {
              results: [],
              subreddit: ''
          },
          mounted: function() {
              var vm = this;
              //when results change, set changes on the vue component
              //instance. Vue's change detection will pick up on these changes
              //and update accordingly
              $scope.$watch(function() {
                  return $scope.results
              }, function(newResults) {
                  if(newResults == null) {
                      return
                  }

                  vm.results = newResults;
                  vm.subreddit = $scope.subreddit;
               })
           },
           methods: {
               //vue component methods can simply call angular service/methods
               onPostNavigate: function(id) {
                   $state.go('post', {id: id, subreddit: $scope.subreddit})
               }
           },
        })

         $scope.$on('$destroy', function() {
             vueInstance.$destroy()
         })
     }
   }
 }

The full code file with this snippet can be found here.

This approach is straightforward: we are using $scope as an event emitter, updating the Vue component state whenever a $scope value changes.  For events occurring in the Vue component tree, they can bubble up to the root Vue component and call an instance method on the root which has access to injected Angular services (e.g. redditService in the code sample above).

Provide the Angular $injector Service to the Vue Runtime

This approach involves taking Angular’s $injector service and…injecting it into Vue via a Vue plugin:

  • Each Vue component can access a registered Angular service (value, factory, service) via the $injectors “get” method
  • This approach prevents the need to pass down data multiple levels to leaf components as those components can access data directly from a service
  • This is a more advanced use of both Angular and Vue as it requires utilizing a Vue plugin and exposes Angular services to child Vue components via the $injector service.

First, we write our Vue plugin:


function injectorWrapper($injector) {
    var injectorPlugin = {
        install: function(Vue, options) {
            Vue.prototype.$injector = function(service){
                return $injector.get(service)
            }
        }
    }

    return injectorPlugin
}

This plugin is then installed on the Vue instance:


function directive($injector) {
    return {
       link: function($scope, elem, link) {
           var plugin = injectorPlugin.plugin($injector);

           //this will register $injector with Vue and make it
           //available in each Vue component instance
           Vue.use(plugin);

           //rest of directive code
       }
    }
 }

Finally, the $injector service is available as a property on a Vue component instance:

//Post is a child component of the Vue component root
var Post = {
    mounted: function () {
        //fetch post information based on route params
        //using angular version of redditService
        var redditService = this.$injector('redditService')
        var params = this.postParams;
        var vm = this;

        redditService.getPostData(params.id, params.subreddit)
            .then(function (post) {
                vm.post = post;
                vm.isLoadingPost = false;
            })
     }
}

The code files with these snippets can be found here, here and here, respectively.

This approach provides us more flexibility in how we access “Angular managed” data as we no longer need to pass data down from the mesh point where we mount our root Vue component on an Angular directive DOM node. However, this approach is slightly more complex, and by using Angular’s $injector service, our Angular code is “bleeding” into our Vue code, creating a tighter coupling.

Note that both strategies require us to call “$destroy” on a Vue instance when the scope of the hosting directive “$destroy” event fires.  Not doing so can result in memory leaks due to Vue instances not being cleaned up.

Conclusion

Do you have to move on to a new age framework, whether it be for a greenfield app or an existing codebase?  Absolutely not!  These libraries and frameworks are tools for you to use to build and ship applications. Use the technology with which you and your team feel most comfortable.  However, integrating newer libraries into your development flow will allow you to access productivity and performance gains. While all new age frameworks offer these same benefits, they vary in terms of cost of setup and difficulty of understanding.

When taking these considerations in mind, it is in my opinion that Vue.js offers the best of both worlds; great performance and developer experience without the cognitive costs and “time to first line of code” in comparison to libraries like React and Angular 2+.  And given its relative simplicity in integrating with an existing Angular 1 codebase, Vue should be your next JavaScript library of choice.

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: