How to use Ember 2 code in your Ember 3 app

Jen Weber
Frontend Weekly
Published in
5 min readAug 13, 2018

Good news! Most Ember 2 blog posts, Stack Overflows, and tutorials are still relevant for learning and debugging Ember 3, which was released in February 2018. With just a couple modifications, you can use older code snippets. We’ll cover what changes to make and a summary of the differences between Ember 2 and 3.

The differences between Ember 2 and 3

Here’s the thing… There isn’t much of a difference that is visible to developers, apart from the way that functions are imported, and you’ll pick that up in a flash.

How is this possible? Ember’s major version releases are done differently than most other JavaScript libraries. Rather than being a time to overhaul a bunch of things and change APIs, they are more like spring cleaning to enable new features to be built. A well-maintained 2.18 app can be upgraded to 3.0 with no change in the code.

A ton of work goes into making this experience possible. You can learn more about some of the behind the scenes changes for 2 → 3 in the release blog post. However, you don’t really need most of that info in order to convert code samples.

Sidenote: Ember has very few major releases because a major release = breaking changes. Ember only break things when it is really worth it, and only with community consensus. It’s easy to assume that more major versions means that a library or framework is more active, but in reality it’s just a warning sign that there might be code churn problems.

Code samples to avoid

A good rule of thumb is that articles and videos created from 2016 onwards are usually helpful. Ember 2 was released in August 2015. I do not recommend looking at code samples older than Ember 1.13, which was the last 1.x release before Ember 2.

Where to get the most up-to-date information

There are a whole bunch of of volunteers who work hard to keep the official site’s resources up to date. The Guides, the official Tutorials, and the API docs should be your first stop. Many authors of articles and videos are contributors to those resources. If something there is out of date or unclear, please open an issue and let them know what needs improvement! It’s really important to speak up, because the more someone works on the docs, the less they can see where others might get stuck.

Making sense of older code samples and explanations

In Ember 3, you only import the methods that you need. This was done to pave the way for future tree shaking features. However, in Ember 1.13–2.15, almost every JavaScript file had a global at the top of it:

import Ember from `ember`;

Ember API methods were accessed using this global Ember, like in this component example:

import Ember from 'ember';

export default Ember.Component.extend({
isAwesome: Ember.computed('model.awesomeness', function() {
return true
})
});

Starting in Ember 2.16, developers could only import what they need:

import Component from '@ember/component';
import { computed } from '@ember/object';

export default Component.extend({
isAwesome: computed('model.awesomeness', function() {
return true
})
});

Take a close look…

  • There are two new import statements that replace import Ember
  • export default Ember.Component became export default Component
  • Ember.computed became simply computed

During Ember 2.16–2.18, developers could use either kind of import and everything would work, and the global Ember was marked as deprecated.

At the release of Ember 3, apps were required to start using the new import-what-you-need approach. The global Ember was removed. While doing the big upgrade, most developers used ember-cli-update to make the necessary changes to their app syntax. They didn’t make these changes by hand, because there are codemods like this one integrated into ember-cli-update.

How to convert these code samples

Ok, so what do you need to do to make these old code examples work in your app?

First, always use the Ember CLI to generate files. It will take care of the main import of Component, Route, Service, etc.

Second, don’t copy/paste over the import Ember from 'ember'. You don’t need it.

Third, look up the API method/property in the Ember API docs for your app’s version. The Home page has a list of the most commonly imported APIs. In the docs, you’ll see the correct import path that you need to add at the top of the file. Alternately, it might be helpful to look at the Ember Guides for some examples of the methods in action, or the official tutorials.

Fourth, change the code so that it uses the imported method. Here are two of the most common modifications:

  • Computed property: add import { computed } from ‘@ember/object’ at the top of the file, and in the code snippet, Ember.computed should be changed to computed
  • Service injection: add import { inject as service } from '@ember/service' at the top of the file. Ember.inject.service should be changed to service

this.get is usually optional in Ember 3, but doesn’t hurt

There’s one thing you should probably know, but don’t need to do anything about. In Ember 2, if you wanted to use a property of an object (like in a Component or Service), you always had to use this.get('somePropertyName'). In Ember 3, you can just do this.somePropertyName for almost everything except properties that are Promise proxies. When you need to use get, you’ll see a warning in the console or linter. Extra this.gets in older code are fine to leave in!

Testing is a little bit different

Previously, testing API methods were part of the main Ember.js codebase, whereas today, they are part of ember-test-helpers. You can find the documentation for the old test helpers in versions 2.15 and earlier of the Ember API Docs. The current 3.x test helpers’ API docs are available here.

Just like before, if you are using old code, you’ll need to change the imports but the API methods themselves are more or less the same. You can take a peek at the codemods used by ember-cli-update to quickly find what to swap out. Here’s the codemod for qunit (the testing framework used by many Ember devs) and the test helpers.

It’s also way easier to inject a service into a test! This article shows how it used to be done, whereas today you can inject a service in a test by using this.owner.lookup('service:servicename').

I recommend Tobias Bieniek’s 2018 EmberConf talk if you want a full comparison:

Getting help

Check out the Ember Community page for links to chat groups, forums, and more. Anyone is welcome to ask questions! Post a link to the blog post, article, or tutorial that you are doing, plus the errors or problems you are having.

After you figure out what was causing the issue, consider commenting with your converted example to help out other learners in the future!

Did I miss anything? Let me know too. Good luck!

PS: It’s important that we all keep an eye out for lessons we can learn from other front end frameworks and tools. I encourage you to submit an article or subscribe to the http://frontendweekly.co/ newsletter. A bunch of my writing is published there, together with tons of other writers, and I’d love to see some more Ember devs in the mix. Ping me if you want help writing!

--

--

Jen Weber
Frontend Weekly

Huge fan of Ember.js, open source, HTML, and accessible, inclusive web apps. www.jenweber.me