Creating a Next Gen JavaScript Application with Aurelia

Share this article

2015 brings with it the finalization of the ECMAScript 6 specification and with that the confidence to build modern, superior applications in JavaScript. The current landscape of JavaScript frameworks is dominated by the recognizable giants AngularJS and React both of which are aiming in some way, shape or form, to incorporate new ES6 features into their paradigms. There is however, another player that while new and relatively secretive, looks elegant in its use of modern JavaScript features. I’d like to take a moment to introduce you to Aurelia.

Aureli-who?

Aurelia is a next generation framework that leverages modern concepts like ES6, Web Components, and modularization to help you develop performant, futureproof applications. Aurelia is the natural progression of Durandal, an AngularJS competitor built by Rob Eisenberg. Aurelia’s history involves a number of encounters with the AngularJS team over the years. It’s for this reason that many aspects of the framework might feel familiar to the AngularJS developers among you.

New Technologies

As I said, Aurelia is a “next generation” framework and as a consequence the tools it uses may be new to some of you. It runs on Node.js, and uses npm but it relies on a few cool new pieces of tech that we’ll look at briefly below:

Gulp

This one isn’t so new but it’s a core part of Aurelia’s setup. We’ll use Gulp to pipe all our files through various tasks to ensure our application is all wired up and ready to go.

ES6 Module Loader Polyfill

The ES6 module loader is a pollyfill for the System dynamic module loader that was part of the original ES6 specification. The System loader is in the process of being written into browser specifications but in the meantime this polyfill provides a futureproof solution that we can use today. The loader allows us to dynamically load modules defined in the ES6 module syntax using the System.import method:
System.import('mymodule').then(function(m) { ... });
In addition to loading ES6 modules, the loader allows to load other module syntaxes through the use of hooks.

SystemJS

With its slightly confusing name, SystemJS is essentially a collection of loader hooks for the ES6 module loader that enable us to load modules from npm, jspm, ES6 Modules and more. You can think of it as a feature rich module loader built on the future proof foundation of the ES6 Module Loader Polyfill.

jspm

jspm is a package manager, like npm, designed to be used with SystemJS. It allows us to install packages from various sources and exposes those to our app so we can easily import them with SystemJS.

Let’s Get Set up

I’m going to assume you’ve already installed Node.js, npm and Git, and that you’re familiar with the use of all of them. We’ll start by cloning the Aurelia example application repository from GitHub
git clone https://github.com/aurelia/skeleton-navigation.git
At this point you might ask: “Why are we cloning their example app rather than starting our own from scratch?”
The reason is that Aurelia is still in an early stage, thus there’s no simple aurelia init command yet that you can run to get your package.json file and everything set up. The repository we cloned acts as a good base for our app. It gives us a directory structure, a package manifest, some testing configuration and more. Hopefully one day there’ll be an installer of sorts or we’ll defer to generators like Yeoman the setup. Since we’re using the repository for its configuration and not for their example app itself, you can go ahead and delete the src/ directory, and the styles/styles.css and index.html files. We’ll create our own shortly. We’ll need to install a few other things in order to install our dependencies and kick start our app: Install gulp globally so that we have access to the gulp CLI:
npm install -g gulp
Then, install jspm globally for the same reason.
npm install -g jspm
Now open the CLI and move to your app’s root directory. Once done, run the command:
npm install
It’ll install our dependencies (from the package.json file) that include among other things:
  • Aurelia tools
  • Gulp plugins
  • Karma packages for testing
Once the process is completed, we’ll install our jspm packages as well using the command:
jspm install -y
This is the bit that actually installs the modules that include Aurelia. Last but not least, let’s install Bootstrap with jspm:
jspm install bootstrap
It’s worth noting that the Aurelia library (contained within these modules) has a number of dependencies on its own, including SystemJS. These will all be installed through dependency management as a result of installing Aurelia itself. I wanted to highlight this point just in case you’re wondering how we have access to things like SystemJS later on despite not having listed it explicitly here in our dependencies.

Time to build an app

We’ve now got a host of tools to help us build our app. What we need next is an index.html page:
<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="jspm_packages/github/twbs/bootstrap@3.3.4/css/bootstrap.min.css">
    <link rel="stylesheet" href="styles/styles.css">
  </head>
  <body aurelia-app>
    <script src="jspm_packages/system.js"></script>
    <script src="config.js"></script>
    <script>
      System.config({
        "paths": {
          "*": "dist/*.js"
         }
      });
      System.import('aurelia-bootstrapper');
    </script>
  </body>
</html>
Let’s step through the contents of <body>. As I mentioned before, SystemJS allows us to use the System.import
method. In this code, we use it to import the aurelia-bootsrapper module which kicks off our Aurelia app. We can reference aurelia-bootstrapper by name thanks to the config.js file that jspm built for us when we ran jspm install -y. It maps the module name, to its versioned source. Pretty nifty stuff. The System.config bit sets up the paths for our modules, i.e. where to start looking for files. Now, create the styles/style.css file and add this code to it:
body { padding-top: 74px; }
You’ll notice that we’re including Bootstrap which we installed earlier. The version may have changed at the time you read this tutorial, so take note of which one jspm installed.

What does the aurelia-bootstrapper do?

The aurelia-bootstrapper module will scan the index.html file for an aurelia-app attribute. If such attribute specifies a value, then the bootstrapper will load the view/module with that name; otherwise it’ll load a view and module called app.html and app.js (which are the defaults). The view will get loaded into the element that has the aurelia-app attribute (in this case the <body> tag). It’ll be wired up to the app.js file. Let’s create an app.js and app.html file in the src directory to see this in action:
export class App {
  constructor() {
    this.name = "Brad";
  }
}
<template>
  Hello, my name is <strong>${name}</strong>
</template>
The first thing you’ll notice is the use of the new ES6 module syntax and the export keyword. You’ll also notice the use of the new ES6 class syntax and abbreviated function signatures. Aurelia, thanks to SystemJS, comes with support for many exciting ES6 features straight out of the box. Here we see that app.js defines a class whose properties are exposed as variables for use in the app.html file. This class is known as a view-model, since it’s a data structure that backs our view. We print out the variables in our template using ES6 string interpolation syntax. As the last note, I want to highlight that all the templates in Aurelia are wrapped in a <template> tag.

Viewing our application in a browser

To get the app up and running in a browser, all we need to do is execute the command:
gulp watch
That’ll do all the magic of compiling ES6, live reload, and so on. You should be able to see your app at http://localhost:9000/. As we expected, we see the contents of our template rendered inside the <bodygt; tag and we see the property interpolated into the template. Our gulpfile has already setup BrowserSync for us so the page will reload if you make any changes.

Time to build our app

In this section, we’ll build a naive Reddit client that has two pages: “Funny” and “Gifs”. We’ll fetch data for each page from Reddit’s API and display a list on each page. When building any application with multiple pages, the core of the application is the router and Aurelia is no different. Let’s change our app.js file, so that it becomes the core module of our app. It’ll be responsible for defining and configuring routing.
import {Router} from "aurelia-router";

export class App {
  static inject() { return [Router]; }

  constructor(router) {
    this.router = router;
    this.router.configure(config => {
      config.title = "Reddit";

      config.map([
        {route: ["", "funny"], moduleId: "funny", nav: true, title: "Funny Subreddit"},
        {route: "gifs", moduleId: "gifs", nav: true, title: "Gifs Subreddit"}
      ]);
    });
  }
}
So, what have we done here? The first line (import {Router} from "aurelia_router") imports the router itself using ES6 module import syntax. Then, in the App class we have a static function called inject. Those of you familiar with AngularJS and not only will already know about dependency injection. The inject function is going to determine, via dependency injection, what parameters will be available in our constructor function. In this instance, a single parameter will be provided and that’s our router. You can see we’ve altered the constructor function to accept that new parameter. Dependency injection is powerful because it allows the loose coupling of modules and hands the control flow up a level meaning we can swap out those dependencies during testing or later on when they’re updated. Now that we have the router available in the constructor of our class, we can use it to set up the routes. First and foremost we set the router as a property of the class itself with this.router = router;
. This is an Aurelia convention and is necessary for routing to work. Note that naming is important in this instance. Secondly, we configure our routes by using the config object provided to us in the callback of this.router.configure. We set a title property that will be used to set the title of our pages. We also pass a list of route definitions to the config.map function. Each route definition has the following pattern:
{
  route: ["", "foo"], // Activate this route by default or when on /foo
  moduleId: "foo", // When active, load foo.js and foo.html (module)
  nav: true, // Add this route to the list of navigable routes (used for building UI)
  title: "Foo" // Used in the creation of a pages title
}
So, in our instance we’ve got two pages that we can visit at /#/funny and /#/gifs, with /#/funny acting as our default page thanks to the ["", "funny"] list of two route patterns. We’ll also need to update app.html to act as our app’s layout file.
<template>
  <a href="/#/funny">Funny</a>
  <a href="/#/gifs">Gifs</a>
  <router-view>
  </router-view>
</template>
Can you see the <router-view></router-view> custom element? This is another built-in piece of Aurelia’s features. You can think of it like an AngularJS directive or just a web component. The view associated with the current route will automatically be loaded into this element. Next, we’ll need to define the two modules: funny and gifs.

Writing our page modules

The “Funny” module

We’ll start with funny and then copy it over as a basis for gifs. Create a /src/funny.js file with the following content:
import {HttpClient} from 'aurelia-http-client';

export class Funny {
   // Dependency inject the HttpClient
  static inject() { return [HttpClient]; }

  constructor(http) {
    this.http = http; // Assign the http client for use later
    this.posts = [];
    this.subreddit_url = "http://reddit.com/r/funny.json";
  }

  loadPosts() {
    // Aurelia's http client provides us with a jsonp method for
    // getting around CORS issues. The second param is the callback
    // name which reddit requires to be "jsonp"

    return this.http.jsonp(this.subreddit_url, "jsonp").then(r => {
      // Assign the list of posts from the json response from reddit
      this.posts = r.response.data.children;
    });
  }

  // This is called once when the route activates
  activate() {
    return this.loadPosts();
  }
}
Also create /src/funny.html as follows:
<template>
  <ul class="list-group">
    <li class="list-group-item" repeat.for="p of posts">
      <img src.bind="p.data.thumbnail" />
      <a href="http://reddit.com${p.data.permalink}">
        ${p.data.title}
      </a>
    </li>
  </ul>
</template>

The “Gifs” module

Let’s simply copy our funny.js and funny.html to src/gifs.js and src/gifs.html respectively. We’ll need to tweak the contents of gifs.js a little.
import {HttpClient} from 'aurelia-http-client';

export class Gifs {
  static inject() { return [HttpClient]; }

  constructor(http) {
    this.http = http;
    this.posts = [];
    this.subreddit_url = "http://reddit.com/r/gifs.json";
  }

  loadPosts() {
    return this.http.jsonp(this.subreddit_url, "jsonp").then(r => {
      this.posts = r.response.data.children;
    });
  }

  activate() {
    return this.loadPosts();
  }
}
Now you should be able to visit localhost:9000/#/gifs to see a list of gif posts and their links.

Improvements to our layout

We can make a couple of improvements to our layout template using Aurelia’s router. Remember the nav:true property we set in our route config earlier? What it does is to add a route to a list that we can iterate over in our view in order to build dynamic navigation. Let’s do that now. Update the contents of app.html as follows:
<template>
<div class="container">
  <ul class="nav navbar-nav navbar-fixed-top navbar-inverse">
    <li repeat.for="navItem of router.navigation" class="${navItem.isActive ? 'active' : ''}">
      <a href.bind="navItem.href">
        ${navItem.title}
      </a>
    </li>
  </ul>

  <router-view></router-view>
</div>
 </template>

Conclusion

Well there you have it! Your first Aurelia application. I’m pretty excited about the future of Aurelia as I think it’s clean and straightforward. Moreover, by using ES6 it keeps everything in reusable, extendable modules. In future tutorials, I’ll look at how we can abstract the duplication between the Gifs and Funny modules, as well as some other improvements and additions to our Reddit client. I’d love to know how your first attempt at app development with Aurelia goes! The complete application that we’ve built during this article can be found here

Frequently Asked Questions about Creating Next-Generation JavaScript Applications with Aurelia

What makes Aurelia a unique JavaScript framework?

Aurelia stands out from other JavaScript frameworks due to its simplicity, modernity, and focus on web standards. It is designed to be simple to understand and use, with a straightforward syntax that reduces the learning curve for developers. Aurelia is also built with modern JavaScript, which means it takes advantage of the latest language features and APIs. Furthermore, Aurelia adheres to web standards, ensuring compatibility and interoperability with other technologies.

How does Aurelia compare to other JavaScript frameworks like Angular or React?

Aurelia, Angular, and React are all powerful JavaScript frameworks, but they have different strengths and use cases. Aurelia is known for its simplicity and adherence to web standards, which makes it a good choice for projects where these factors are important. Angular is a comprehensive framework that includes a wide range of tools and features, making it suitable for large-scale applications. React, on the other hand, is a library for building user interfaces, and it’s often used in combination with other libraries or frameworks.

Can I use Aurelia with TypeScript?

Yes, Aurelia is designed to work seamlessly with TypeScript. In fact, Aurelia’s own source code is written in TypeScript, which demonstrates the framework’s commitment to this statically typed superset of JavaScript. Using Aurelia with TypeScript can help you catch errors early, improve code readability, and take advantage of advanced language features like decorators and interfaces.

How can I get started with Aurelia?

To get started with Aurelia, you’ll first need to install Node.js and npm on your machine. Then, you can install the Aurelia CLI, which is a command-line tool that helps you create, develop, and test Aurelia applications. Once the CLI is installed, you can create a new Aurelia project with a single command. From there, you can start building your application by adding components, services, and routes.

What is Aurelia’s approach to data binding?

Aurelia supports two-way data binding, which means changes in the model automatically update the view, and vice versa. This makes it easy to keep your user interface in sync with your application state. Aurelia’s data binding system is also flexible and powerful, supporting a variety of binding types and syntaxes. For example, you can bind to properties, events, or even custom attributes.

Can I use Aurelia for mobile app development?

While Aurelia is primarily designed for building web applications, it can also be used for mobile app development in combination with technologies like Cordova or Electron. These tools allow you to package your Aurelia application as a native mobile app, which can be distributed through app stores and installed on mobile devices.

How does Aurelia handle routing and navigation?

Aurelia includes a flexible and powerful router that helps you manage navigation in your application. The router allows you to define routes, navigate between views, and handle parameters and query strings. It also supports child routers, which can be used to create complex navigation structures.

What kind of support and community does Aurelia have?

Aurelia has a vibrant and active community of developers who contribute to the framework, create plugins, and help each other solve problems. There are also numerous resources available for learning Aurelia, including the official documentation, tutorials, and online courses. In addition, the Aurelia team provides professional support and consulting services.

Can I use Aurelia with existing JavaScript libraries or frameworks?

Yes, Aurelia is designed to be friendly to other technologies. You can use it alongside existing JavaScript libraries or frameworks, or even integrate it into an existing project. This makes Aurelia a flexible choice that can adapt to your specific needs and technology stack.

How does Aurelia handle testing?

Aurelia supports unit testing and end-to-end testing out of the box. The framework includes a test runner and utilities for mocking and spying, which make it easy to write and run tests for your application. Aurelia also integrates well with popular testing libraries and frameworks, so you can choose the tools that best fit your testing strategy.

Brad BarrowBrad Barrow
View Author

Brad is a front-end developer and designer living in Melbourne and working with the team at SitePoint. He tries to keep on top of the ever changing front-end universe by eating JavaScript/CSS for breakfast.

aureliaAurelioDECMAScript6frameworkjavascript frameworknode.jsnpm
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week