Managing Dependencies

Ember CLI uses Bower for dependency management.

Bower Configuration

The Bower configuration file, bower.json, is located at the root of your Ember CLI project, and lists the dependencies for your project. Changes to your dependencies should be managed through this file, rather than manually installing packages individually.

Executing bower install will install all of the dependencies listed in bower.json in one step.

Ember CLI is configured to have git ignore your bower_components directory by default. Using the Bower configuration file allows collaborators to fork your repo and get their dependencies installed locally by executing bower install themselves.

Ember CLI watches bower.json for changes. Thus it reloads your app if you install new dependencies via bower install --save <dependencies>.

Further documentation about Bower is available at their official documentation page.

Compiling Assets

In your Brocfile.js specify a dependency before calling app.toTree(). You can only import assets that are within the bower_components or vendor directories. The following example scenarios illustrate how this works.

Javascript Assets

Standard Non-AMD Asset

Provide the asset path as the first and only argument:

1 app.import('bower_components/moment/moment.js');

From here you would use the package as specified by it’s documentation, usually a global variable. In this case it would be:

1 import Ember from 'ember';
2 /* global moment */
3 // No import for moment, it's a global called `moment`
4 
5 // ...
6 var day = moment('Dec 25, 1995');

Note: Don’t forget to make JSHint happy by adding a /* global MY_GLOBAL */ to your module, or by defining it within the predefs section of your .jshintrc file.

Standard AMD Asset

Provide the asset path as the first argument, and the list of modules and exports as the second:

 1 app.import('bower_components/ic-ajax/dist/named-amd/main.js', {
 2   exports: {
 3     'ic-ajax': [
 4       'default',
 5       'defineFixture',
 6       'lookupFixture',
 7       'raw',
 8       'request',
 9     ]
10   }
11 });

To use this asset in your app, import it. For example, with ic-ajax, when to use ic.ajax.raw:

1 import { raw as icAjaxRaw } from 'ic-ajax';
2 //...
3 icAjaxRaw( /* ... */ );
Environment Specific Assets

If you need to use different assets in different environments, specify an object as the first parameter. That object’s key should be the environment name, and the value should be the asset to use in that environment.

1 app.import({
2   development: 'bower_components/ember/ember.js',
3   production:  'bower_components/ember/ember.prod.js'
4 });

If you need to import an asset in one environment but not import it or any alternatives in other environments then you can wrap app.import in an if statement.

1 if (app.env === 'development') {
2   app.import('vendor/ember-renderspeed/ember-renderspeed.js');
3 }
Customizing a built-in Asset

This is somewhat non-standard and discouraged, but suppose that due to a requirement in your application that you need to use the full version of Handlebars even in the production environment. You would simply provide the path to the EmberApp constructor:

1 var app = new EmberApp({
2   vendorFiles: {
3     'handlebars.js': {
4       production: 'bower_components/handlebars/handlebars.js'
5     }
6   }
7 });
Test Assets

You may have additional libraries that should only be included when running tests (such as qunit-bdd or sinon). These can be merged into your assets in your Brocfile.js:

 1 var EmberApp = require('ember-cli/lib/broccoli/ember-app');
 2 var pickFiles = require('broccoli-static-compiler');
 3 
 4 var app = new EmberApp();
 5 
 6 var qunitBdd = pickFiles('bower_components/qunit-bdd/lib', {
 7     srcDir: '/',
 8     files: ['qunit-bdd.js'],
 9     destDir: '/assets'
10 });
11 
12 module.exports = app.toTree(qunitBdd);

Notes: - Be sure to add the appropriate script tag for your test library. - The first argument to pickFiles is a tree. This means that doing pickFiles('bower_components', ...) will cause all files in /bower_components to be watched. If you get a Error: watch EMFILE during build, this could be the culprit. Consider using a more specific path as tree or use pickFiles(unwatchedTree('bower_components'),...) from broccoli-unwatched-tree.

...
<script src="assets/qunit.js"></script>
<script src="assets/qunit-bdd.js"></script>
...

Styles

Static CSS

Provide the asset path as the first argument:

1 app.import('bower_components/foundation/css/foundation.css');

All style assets added this way will be concatenated and output as /assets/vendor.css.

Dynamic Styles (SCSS, LESS, etc)

The vendor trees that are provided upon instantiation are available to your dynamic style files. Take the following example (in app/styles/app.scss):

1 @import "bower_components/foundation/scss/normalize.scss";

Other Assets

Using app.import()

All other assets like images or fonts can also be added via import(). By default, they will be copied to dist/ as they are.

1 app.import('bower_components/font-awesome/fonts/fontawesome-webfont.ttf');

This example would create the font file in dist/font-awesome/fonts/fontawesome-webfont.ttf.

You can also optionally tell import() to place the file at a different path. The following example will copy the file to dist/assets/fontawesome-webfont.ttf.

1 app.import('bower_components/font-awesome/fonts/fontawesome-webfont.ttf', {
2   destDir: 'assets'
3 });
Using broccoli-static-compiler

With the broccoli-static-compiler package, (parts of) a bower-installed package can be used as assets as-is. First ensure that the Broccoli package needed to build are installed:

npm install --save-dev broccoli-static-compiler

Add this import to the top of Brocfile.js, just below the EmberApp require:

1 var pickFiles = require('broccoli-static-compiler');

At the bottom of Brocfile.js we merge assets from a bower dependency with the main app tree:

 1 // Remove this line:
 2 // module.exports = app.toTree()
 3 
 4 // Copy only the relevant files. For example the WOFF-files and stylesheets for a webfont:
 5 var extraAssets = pickFiles('bower_components/a-lovely-webfont', {
 6    srcDir: '/',
 7    files: ['**/*.woff', '**/stylesheet.css'],
 8    destDir: '/assets/fonts'
 9 });
10 
11 // Providing additional trees to the `toTree` method will result in those
12 // trees being merged in the final output.
13 module.exports = app.toTree(extraAssets);

In the above example the assets from the fictive bower dependency called a-lovely-webfont can now be found under /assets/fonts/, and might be linked to from index.html like so:

<link rel="stylesheet" href="assets/fonts/lovelyfont_bold/stylesheet.css">