The Eisenberg Effect

Aurelia May Status and Releases

Introduction

Rob Eisenberg

Rob Eisenberg

Sr. Program Manager on docs.microsoft.com. Creator of Caliburn, Caliburn.Micro, Durandal and Aurelia. My opinions are my own.


Aurelia May Status and Releases

Posted by Rob Eisenberg on .
Featured

Aurelia May Status and Releases

Posted by Rob Eisenberg on .

Today's release comes with what we believe is the final set of big breaking changes. We've also got new features, improvements and a few other goodies.

Changes

ES2016 Metadata

There's currently work being done to standardize how metadata is attached to classes, members, etc. In this release, we remove Aurelia's metadata implementation and replace it with the emerging ES2016 standard. This causes breaking changes if you were working directly with metadata. However, if you were using Aurelia's decorators or the fallback apis, you should not see any changes, since this is mostly an implementation detail. If you are interested in the emerging Metadata Reflection API, you can read the detailed spec and have a look at the polyfill that we've incorporated.

Positive Side Effects

Now that we've changed the way that metadata works, we've been able to remove some inheritance that was previously required by the framework. For example, in the dependency injection library, we were able to remove the base classes InstanceActivator and Registration. Now, if you want to customize how DI works using these extensibility points, you just implement a class with a particular api and then use the decorator api to associate it with a class. A related benefit is that, by removing some inheritance throughout the framework, we do get a performance increase in certain areas.

There's another benefit to this that relates to yesterday's TypeScript 1.5 Beta release. The latest version of TypeScript will emit type metadata for classes using the Reflect Metadata API if you compile your code with the --emitDecoratorMetadata flag. To support this, there's a new decorator we've added which you can use on your TypeScript classes:

@autoinject()
export class Foo {  
  constructor(public bar:Bar){}
}

By using @autoinject on a class in combination with the --emitDecoratorMetadata compiler flag, Aurelia's dependency injection system will be able to automatically determine the constructor types. Sweet!

Enumerations

While JavaScript doesn't have an enumeration type, there are several areas in Aurelia where we use enumeration-ish values. We've made a couple of breaking changes in order to make this consistent across all our libraries. All enumerations are now named using singular words. This means that the levels enum in the logging library is now named logLevel and is exported as follows:

export var logLevel = {  
  none: 0,
  error: 1,
  warn: 2,
  info: 3,
  debug: 4
};

The binding modes, which were not grouped together at all, are now grouped under the export bindingMode as follows:

export var bindingMode = {  
  oneTime: 0,
  oneWay: 1,
  twoWay: 2
};

The same type of change was made to the router's, also formerly ungrouped, activation strategies:

export var activationStrategy = {  
  noChange: 'no-change',
  invokeLifecycle: 'invoke-lifecycle',
  replace: 'replace'
};

Naming Consistency

There were a few places across the libraries where different naming schemes were being used. We've tried to patch those up. In particular, we've replaced the use of "uri" through our APIs with a consistent use of "url". This is a breaking API change to HttpRequestBuilder and HttpRequestMessage. To update, replace uses of withUri, withBaseUri, and uri with withUrl, withBaseUrl, and url, as appropriate. Another place was our plugin API. Previously plugins needed to implement an install method but everything else in Aurelia used a configure terminology. We've change plugins to now use a configure method so that it's the same everywhere.

Routing

By far, the biggest set of changes in these releases are to the router. There were a number of long-standing issues with the router that have now been resolved, thanks to the excellent work of core team member Bryan Smith.

Router Configuration

Prior to this release, configuring the router has been a bit odd. One needed to have a router injected and then set it as a property named "router". Additionally, if you wanted to inject a router to control navigation but not to set up a child navigation, there were problems. To address these issues, we've changed the way configuring routers works. To configure a router, you now implement a configureRouter method. The method will receive the configuration object as its first parameter and the router instance as is second parameter. If you need the router, perhaps because you want to use the navigation model, then you can just store it, but if not, you can ignore it. Here's a look at the navigation skeleton's app class after this change:

export class App {  
  configureRouter(config, router){
    config.title = 'Aurelia';
    config.map([
      { route: ['','welcome'],  moduleId: './welcome',      nav: true },
      { route: 'flickr',        moduleId: './flickr',       nav: true },
      { route: 'child-router',  moduleId: './child-router', nav: true }
    ]);

    this.router = router;
  }
}

As as result of this change, you can now have a router injected into any class without accidentally creating a new child navigation system. The router that is injected will be the closest router in the navigation hierarchy and can be used to do programmatic navigation or route generation.

Route Generation

The latest version of the router now has full support for route generation so that you no longer need to hard-code route patterns in your HTML or construct them in your JavaScript. To leverage this, simply name the route in your configuration. If you want to generate a route based on data in JavaScript, you use the generate method like so:

let href = router.generate(routeName, params);  

The generation mechanism understands whether you are running in hash change or push state mode, how your routes are parameterized and how to construct query strings. Just give it the name and a params object with key/value pairs for the route parameters and query string data.

You will often want to generate routes in your HTML so that you can link to different app states, but without hardcoding the route patterns. Aurelia now provides a route-href custom attribute that you can use to accomplish this. It takes route and params properties. Here's an example using it, based on our contact app sample:

<a route-href="route: contacts; params.bind: {id:contact.id}"></a>  

This will generate the route named "contacts" based on the provided "id" parameter.

Activation Parameters

As part of the work on route generation, and in an effort to encapsulate knowledge of route patterns, we've changed the way the canActivate and activate hooks receive data. We've simplified the provided data by combining the route parameters and query string values into a single key/value pair object. This makes the api mirror the generation api and allows the developer to not need to remember or lookup wether a given input is coming from a route parameter or a query string. The updated lifecycle method signature is as follows:

activate(params, config, instruction) { ... }  

Updating Aurelia

As a reminder, these releases have breaking changes, so you cannot do a simple jspm update. JSPM is smart in the way that it follows semver, and it won't let you break your app on accident. I recommend using jspm install for each "top level" Aurelia library. Just look in your package.json file, in the jspm section and be sure to re-install all the Aurelia dependencies listed there.

Status

This has been a big release, and over the last month or so we've been making regular breaking changes. We believe that this release marks the end of the sweeping breaking changes to common use APIs. We are still in a pre-beta state, so we do expect there to be more changes, but changes after this point are likely to be much smaller and perhaps not effect you at all. As has been our practice, we will continue to communicate openly with you about everything we've been doing.

Performance

This release is both smaller and faster than previous releases. While we haven't done most of our serious perf work yet, we have optimized our compiler options to reduce code size and use more performant transpilation strategies. We've also been doing some work in our templating engine to optimize specific use cases which occur frequently.

There is major work still coming up here. First you will see the introduction of the "view cache"...or rather I should say the re-introduction of it. This is a concept from Durandal, circa 2012, where we had the idea to re-use view instances. In Durandal the implementation had some quirks and wasn't quite as flexible as needed due to our reliance on 3rd party libraries. In Aurelia, we don't have that problem and will be able to implement something quite powerful. Be on the lookout for that soon.

The second major advance that is coming is in our databinding system. We are going to rework portions of the internal implementation to drastically improve performance and reduce memory. Once that is complete, we'll be able to add a few more features to the binding engine that we really want to add.

Continued Communication

We've made it a goal to have at least one blog post on the Durandal company blog every week, so you have constant content informing you of the project status, releases and cool features. You've had the opportunity to hear from various members of our core team on a variety of topics from adaptive databinding to custom element creation. We're going to continue right along this path and next week you'll get to hear from core team member Mike Graham about how we are enabling TypeScript developers to have an awesome experience with Aurelia.

This isn't good enough though. We want to take it up a notch. In an effort to improve our project organization and give you further visibility into our work, we've adopted ZenHub. If you would like to have deeper insight into our development process, you can now install the ZenHub Chrome Extension and visit any of our repository's "boards". These boards will show you who is working on what, what is planned next, what is under review and what is recently finished. You can get an overview of all Aurelia work by visiting the framework board and selecting "show all" in the upper left corner of the board.

Rob Eisenberg

Rob Eisenberg

http://www.bluespire.com

Sr. Program Manager on docs.microsoft.com. Creator of Caliburn, Caliburn.Micro, Durandal and Aurelia. My opinions are my own.

View Comments...