21 January 2015

Using ES6 with your AngularJS project

Earlier this month Glen Maddern (aka. The <x-gif> guy) posted an article, Javascript in 2015, with a YouTube video giving "A brief tour of JSPM, SystemJS & ES6 features".
If you haven't seen it already, go take a look.

In a short time he has a front-end application written in ES6 running, with modules being loaded and transpiled (via Traceur) by SystemJS.  And at the end he creates a self-executing, minified bundle of that application code, including source maps.

These tools make it easy to start using ES6 now with your existing AngularJS applications - which will almost certainly be step 1 on the migration plan to Angular v2.0. Even without that, the goodies from ES6 are too good to pass up.

As a demonstration, we're going to take angular-seed, update it to ES6 using SystemJS, bundle the app for production with systemjs-builder, and configure Karma to run unit tests using the karma-systemjs plugin.

SystemJS Setup

OK - lets get started.
We're going to clone an angular-seed repo, switch to a new es6 branch, then install dependencies from npm and bower. The dependencies for angular-seed are a bit old, so we've updated them too:

git clone https://github.com/angular/angular-seed.git
cd angular-seed
git checkout -b es6
npm install --save-dev systemjs-builder karma-systemjs karma#~0.12 karma-chrome-launcher karma-firefox-launcher karma-jasmine
bower install -f -S angular#1.3.x angular-route#1.3.x angular-mocks#~1.3.x system.js

Next thing we need is a config file for SystemJS: `app/system.config.js`. This is where we tell SystemJS how to find certain modules.  In this case, we're going to map the module names 'angular' and 'angular-route' to their long paths:

Next we'll change `app/index-async.html` to use SystemJS rather than angular-loader:

Last thing to do is add `import` statements to `app/app.js` to include the rest of the application, as it's what will be loaded by `System.import('app')`:

Now if you load up `app/index-async.html` using a local webserver (The one included with angular-seed start with `npm start`) you should see the angular-seed application running as normal, only it's been loaded as a set of ES6 files.

This is just the bare minimum required to get existing code to ES6 using SystemJS.
You can add more ES6 syntax and rearrange the modules as you like.

Here's my suggestions:

  • Use classes for Controllers (Controller as), Services (.service()), and Providers
  • Use ES6 modules over angular modules
  • Use arrow functions - cause they're sugary sweet!

Bundling for Production

With our SystemJS config file already in place, we only need to pass that into systemjs-builder with a slight tweak to bundle our code for production. This is a simple node script you can run with `node bundle.js` that will bundle all the modules imported by `app/app.js` and output the result to `app/bundle.js`:

And finally we change `app/index.html` to include `traceur-runtime.js` and the `bundle.js` file we just created:

Unit Testing

Karma works like most a typical browser application: Load all <script/> tags, then start the application `onload`. In this case, we want Karma to let SystemJS handle loading everything, then start the test runner once everything is ready.  This is essentially what karma-systemjs does for us.

First we need to adjust `karma.conf.js`:

Next we update our test suites to act like ES6 modules - importing the code to be tested, along with any dependency libraries.

Note how `module()` has been changed to `angular.mock.module()`.

And that's it.
An existing AngularJS project converted over to using ES6 with SystemJS, with working unit tests and a means of generating bundles for production.
You can find the complete code here: https://github.com/rolaveric/angular-seed/tree/es6

Jason Stone