Our transition to Ember 1.13

Posted by Pepe on May 7, 2016

With this post we want to share the changes we made to migrate to the latest version of Ember.js: Ember 1.13. Although most of the issues are called out (via the Ember Inspector browser extension) by the deprecation system and clearly detailed in the respective transition guides, this information may be of interest to other application developers.

emberjs.jpg

To put this in context, less than a year ago, Load Impact decided to radically improve our user experience. The team prepared to rebuild the entire frontend, opting for a Single-Page Application, moving more logic to the client side.

We chose Ember.js for much the same reasons expressed in the article Ember.js: An Antidote To Your Hype Fatigue by Godfrey Chan.

From the outset of the rewrite our journey has been a tenacious organizational effort to build an intuitive load testing platform to help developers understand their system capacity and performance over time.

Our new app started out using Ember 1.7.0-beta.2 and Ember Data 1.0.0-beta.9 and has since gone through multiple migrations. Our goal was to continuously migrate to newer release versions of Ember and Beta versions for Ember Data as they were released.

In most of the upgrades we discovered some wrong uses of Ember on our part, a perfect time to improve our existing tests and test coverage. It also presented an opportunity to refactor code, removing the use of internal Ember APIs we had initially been relying on.

Many of our transition pains come from the fact that we are not currently using Ember-CLI (instead, we use Broccoli as a build and asset pipeline tool with similar configuration to Ember-CLI). But we are confident those pains will disappear when we eventually migrate over to Ember-CLI.

The Ember 1.13.2 transition

Since HTMLBars landed, we have refactored our view/component layer to conform to the new Ember APIs and future direction. Every upgrade has been a smooth process mainly helped by the release announcement, the deprecation guide and the EmberJS Slack community.

Coming from 1.12.1 version, some of our changes have been:

New template compilation

Change to use `Ember.HTMLBars.template` to compile our templates. The old and new version are available here.

Component rename

We were extending the `ComponentLookup` instance to support our folder structure in our components folder, which we find useful when having more than 80 components. The component must always be dasherized, so we changed as follows:

chart/trending.js   → chart/trending-component.js
{chart--trending} → {chart/trending-component}

Not all helpers support a javascript array instance of string elements

Not sure if the each helper is intended to support this case, but the following case failed:

{#each progressContent as |item| }
   {unbound item}
{/each}

Replace Em.View.views with lookup to `view-registry:main`

Not sure if Em.View.views is a public API, but we find it useful in some situations where a parent view needs to access a child view by id (usually supplied by a DOM event):

  var view = this.container.lookup('-view-registry:main'>)[id];      

Standardize the helper creation

We now use Helper.helper or Helper.extend to create all our helpers as described on the new Helper API announcement, moving out `makeBoundHelper` and `function helpers`.

Remove other deprecations

Use Em.Service for service instances, use component block info in our templates, remove the use of routable views, remove array and reduced computed properties.

At this time (11 days after the 1.13.2 release), only a few regression errors have been reported which we haven’t experienced in our app.

The Ember Data 1.13.4 transition

Because of Ember Data’s long running beta status and as a result history of breaking changes, most of our unit tests — approximately 65 percent — are written to assert our Ember Data customizations don’t result in any unexpected bugs when migrating to future versions of Ember Data.

Having a decent test coverage in this part of our app has been a very important factor in making our Ember Data migration experience a pleasant one.

As always, the Ember Data team has provided a detailed transition guide in the Ember 1.13 announcement.

Coming from 1.0.0.beta.17 version, some of our changes have been:

Using Babel and feature flag to build Ember Data

Ember Data is a submodule dependency which is built in every asset creation process. This special configuration based on the Ember Brocfile has given us the possibility to easily debug Ember Data what has been useful in many cases.

Avoid the use of the Snapshot API

  
  serializer.serialize(newSnapshot(test)); 
  test.serialize()

Overwriting the service store after the `store` initializer.

I think this step is not going to be needed if you follow the ember-cli convention, but this was not our case:

import ApplicationStore from 'app/data/store';
export default {
  name: 'setup-store',
  after: ['store'],
  initialize: function(registry, application) {  
    registry.register('service:store', ApplicationStore);
  }
}    

New Errors API

This API change needed more changes and tests caused by the integration between our backend and client validations with the UI.

The backend uses a custom error format which must be transformed by the adapter to convert to the JSON API format expected by the InvalidError class.

After the JSON API transformation, the InvalidError must be normalized through the serializer `extractErrors` method, which can be used to invalidate the model or be bound to our controllers, in order for those errors be shown on the related and specific template UI.

Using newSerializerAPI

We only needed to setup the isNewSerializer property to true and rename our extended methods.

New adapter hooks

Define the hooks to replicate our current behaviour:

shouldReloadAll: function(store, snapshotRecordArray) {
  return true
};
shouldBackgroundReloadAll: function(store, snapshotRecordArray) {
  return true;
},
shouldReloadRecord: function(store, snapshot) {
  return false;
},
shouldBackgroundReloadRecord: function(store, snapshot) {
  return false;
},

Adopt the new find methods

Internal API Change to JSON API

Now, we either use store.push({JSON API format}) or store.push(store.normalize({Server format}) when necessary.

Remove use of store.filter

For this specific case we use Computed Properties based on the returned array and additional filter properties.

Other deprecations

There were still some deprecations to remove as the use of typeKey property instead of modelName that as always, we only had the read the deprecation warnings to know how to proceed.

Four months after the release of our new frontend, our productivity and customer satisfaction has improved. Rewriting the frontend code from scratch turned out NOT to be suicide in our case, despite the warning from tech mogul Steve Blank.

Another benefit to us has been the ability to easily upgrade our framework dependencies with the maturity and stability that our product needs.

Load Impact would like to sincerely thank every member of the fantastic EmberJS community for their invaluable dedication and for making the “stability without stagnation principle” real and tangible.

Topics: ember 1.13, ember, user experience, frontend, frontend development, user interface, ember.js, Blog, UX, UI

Popular posts

Posts by Topic

see all