At Second Street, we create white-label software that enables media companies to run contests and promotions. We build our front end with Ember.js, a framework for creating exactly the kind of ambitious web applications we pride ourselves in providing to our customers. And because we have such a wide array of contests and promotions, we have a similarly large number of Ember applications, all sharing a common core.

With the advent of Ember CLI and Ember CLI Addons for shared functionality, it's now quite simple to create multiple applications that share a common core. This blog post is a quick overview of our recent effort to extract that common functionality into an ember-addon that we can include in all of our applications.

Understanding Addons

There are two ways that an ember-addon can provide functionality to your Ember CLI applications:

  1. The addon's application tree will be merged with the your application's tree. These files can be referenced via your app's namespace, such as import FooController from 'my-app/controllers/foo';.
  2. The addon's other logic can be imported by your application's files. These files are referenced via the addon's namespace, such as import bar from 'my-addon/utils/bar';.

These are not mutually exclusive! A single ember-addon can provide both an application tree to share models, initializers, and such and other logic to be imported into your application's individual files.

Measure Twice

Any files that exist in the addon's app/ folder will be merged with the application's application tree. Any files that exist in the addon's addon/ folder will be available for import into the application's files.

As a general rule, anything that is automatically looked up by the resolver should be merged into your application tree, and anything you import manually should be in your addon's namespace.

The Application Tree

If your applications will share any of the following, it's probably a good idea to put these into the addon's app/ folder, to be merged into your application tree. See the Ember CLI documentation for descriptions about what goes in these files and directories.

  • adapters/application.js
  • components/
  • helpers/
  • initializers/
  • models/
  • serializers/application.js
  • templates/partials/
  • transforms/

If you need to import these into your including application's files, you'll use your own application's namespace. For example:

import Tribble from 'my-application/models/tribble';  

Addon Files

Shared versions of the following are better suited to exist in the addon's addon/ folder, so they stay in the addon's namespace.

  • adapters/
  • mixins/
  • serializers/
  • utils/

Whenever you import these into your including application's files, you'll use the addon's namespace. For example:

import Communicator from `my-addon/utils/communicator`;  

Cut Once

To begin the process, run the following commands, changing my-addon to your addon's name:

ember new my-addon && cd my-addon  
ember generate addon my-addon  
mkdir addon  

Move the files as planned above from their existing locations in your application to the appropriate places in the addon. Change any import declarations to reference the new namespaces and paths, and make the following edits to package.json.

{
  "devDependencies": {
    "my-addon": "*"
  }
}

If you want to have the addon locally instead of publishing it to the public npm registry, edit package.json again:

{
  "scripts": {
    "preinstall": "npm link ../my-addon",
    "preupdate": "npm link ../my-addon"
  }
}

Now you're sharing code between your ember applications and keeping your entire line of products DRY!