When working on an Ember app, sometimes you may want to customize how certain kinds of assets are handled. This is referred to as "asset compilation."
For information on stylesheets, please see the dedicated section, Stylesheet compilation
Raw Assets
To include images, fonts, or other assets, place them in the public/assets
directory.
For example, if you place logo.png
in public/assets/images
, you can reference it in
templates with assets/images/logo.png
or in stylesheets with
url('/assets/images/logo.png')
.
In production builds, these assets are fingerprinted, but all references are also automatically updated. This functionality comes from broccoli-asset-rev. Be sure to check out all the options and usage notes.
JS transpiling
Ember CLI automatically transpiles future JavaScript (ES6/ES2015, ES2016 and beyond) into standard ES5 JavaScript that runs on every browser using Babel JS with the Ember CLI Babel addon.
Internally, Ember CLI Babel uses babel-preset-env
, which figures out which parts of your code
need to be transpiled to ES5 by analyzing your project's browser support targets. A target
is a special keyword
that maps to a browserlist support rule. These are defined in your
config/targets.js
file, which Ember CLI generates like so:
'use strict';
const browsers = [
'last 1 Chrome versions',
'last 1 Firefox versions',
'last 1 Safari versions'
];
const isCI = !!process.env.CI;
const isProduction = process.env.EMBER_ENV === 'production';
if (isCI || isProduction) {
browsers.push('ie 11');
}
module.exports = {
browsers
};
(If these values look familiar, they're the same exact values used by the popular Autoprefixer project. Autoprefixer has an online version that allows you to enter your non-prefixed CSS and gives you a prefix-added CSS.)
If you need more fine-grained customization over the way that babel-preset-env
transforms your code,
set any of the babel-preset-env options on your application's babel
hash in ember-cli-build.js
.
For example, if you wanted to explicitly exclude generator function transpilation from your output, your configuration would look like this:
/* eslint-env node */
'use strict';
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp(defaults, {
babel: {
exclude: [
'transform-regenerator',
// ...more options
]
}
});
//...
return app.toTree();
};
As of Version 2.13, Ember CLI uses Babel 6.X for transpilation. Ember CLI versions prior to 2.13 use Babel Babel 5.X, and you can check its documentation for a comprehensive list of all available transformations and options.
Source maps
Ember CLI supports producing source maps for your concatenated and minified JS source files.
Source maps are configured by the EmberApp sourcemaps
option, and
are disabled in production by default. Pass sourcemaps: {enabled: true}
to your EmberApp constructor to enable source maps for JavaScript. Use the extensions
option to add other formats, such as CSS: {extensions: ['js', 'css']}
. JS is supported out-of-the-box. CSS is not currently supported. For other source formats, refer to their addons.
Default ember-cli-build.js
:
'use strict';
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp(defaults, {
// Add options here
});
// Use `app.import` to add additional libraries to the generated...
return app.toTree();
};
};
Minifying
Compiled css-files are minified by ember-cli-clean-css
, or other registered CSS minifiers,
if they are installed locally. You can pass minifer-specific options to them using
the minifyCSS:options
object in your ember-cli-build. Minification is enabled by
default in the production-env and can be disabled using the minifyCSS:enabled
switch.
Similarly, the js-files are minified with ember-cli-terser
in the production environment by default. You can pass custom options to the minifier via the
ember-cli-terser:options
object in your ember-cli-build. To enable or disable JS minification
you may supply a boolean value for ember-cli-terser:enabled
.
For example, to disable minifying of CSS and JS, add in ember-cli-build.js
:
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp(defaults, {
'ember-cli-terser': {
enabled: false
},
minifyCSS: {
enabled: false
}
});
//...
return app.toTree();
};
More details on available options to customize JavaScript minification can be found in
ember-cli-terser
docs.
Note: ember-cli-uglify
was renamed to ember-cli-terser
with the 4.0.0 release. This change is part of Ember CLI's default blueprint since 3.21.1. Projects still using ember-cli-uglify
can find its configuration options in the ember-cli-uglify
docs.
Exclude from minification
Some files should be excluded from minification, such as copied-and-pasted third-party scripts that are already minified.
To exclude assets from dist/assets
from being minified, one can pass options for
broccoli-uglify-sourcemap like so:
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp(defaults, {
minifyJS: {
options: {
exclude: ["**/vendor.js"]
}
}
});
//...
return app.toTree();
};
This would exclude the resulting vendor.js
file from being minified.
Fingerprinting and CDN URLs
Fingerprinting is done using the addon broccoli-asset-rev (which is included by default).
When the environment is production (e.g. ember build --environment=production
),
the addon will automatically fingerprint your JS, CSS, PNG, JPG, and GIF assets
by appending a md5 checksum to the end of their filename
(e.g. assets/yourapp-9c2cbd818d09a4a742406c6cb8219b3b.js
). In addition, your
HTML, JS, and CSS files will be re-written to include the new name. There are
a few options you can pass into EmberApp
in your ember-cli-build.js
to customize
this behavior.
enabled
- Default:app.env === 'production'
- Boolean. Enables fingerprinting if true. True by default if current environment is production.exclude
- Default:[]
- An array of strings. If a filename contains any item in the exclude array, it will not be fingerprinted.ignore
- Default:[]
- An array of strings. If a filename contains any item in the ignore array, the contents of the file will not be processed for fingerprinting.extensions
- Default:['js', 'css', 'png', 'jpg', 'gif', 'map']
- The file types to add md5 checksums.prepend
- Default:''
- A string to prepend to all of the assets. Useful for CDN URLs likehttps://subdomain.cloudfront.net/
replaceExtensions
- Default:['html', 'css', 'js']
- The file types to replace source code with new checksum file names.customHash
- When specified, this is appended to fingerprinted filenames instead of the md5. Passnull
to suppress the hash, which can be useful when usingprepend
.
As an example, this ember-cli-build
will exclude any file in the fonts/169929
directory as well as add a CloudFront domain to each fingerprinted asset.
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp({
fingerprint: {
exclude: ['fonts/169929'],
prepend: 'https://subdomain.cloudfront.net/'
}
});
//...
return app.toTree();
};
The end result will turn
<script src="assets/appname.js">
background: url('/images/foo.png');
into
<script src="https://subdomain.cloudfront.net/assets/appname-342b0f87ea609e6d349c7925d86bd597.js">
background: url('https://subdomain.cloudfront.net/images/foo-735d6c098496507e26bb40ecc8c1394d.png');
You can disable fingerprinting in your ember-cli-build.js
:
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp({
fingerprint: {
enabled: false
}
});
//...
return app.toTree();
};
Or remove the entry from your EmberApp
and broccoli-asset-rev
from your package.json
.
Application configuration
Application configurations from your ember-cli-build.js
file will be stored inside a
special meta tag in dist/index.html
.
sample meta tag:
<meta name="user/config/environment" content="%7B%22modulePre.your.config">
This meta tag is required for your Ember application to function properly.
If you prefer to have this tag be part of your compiled JavaScript files
instead, you may use the storeConfigInMeta
flag in ember-cli-build.js
.
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp({
storeConfigInMeta: false
});
//...
return app.toTree();
};
Configuring output paths
The compiled files are output to the following paths:
Assets | Output File |
---|---|
app/index.html |
index.html |
app/**/*.js |
/assets/application-name.js |
app/styles/app.css |
/assets/application-name.css |
app/styles/**/*.css |
/assets/application-name.css |
JavaScript files you import with app.import |
/assets/vendor-537734ed4a55f6509f3f8aa6d17afb80.js |
CSS files you import with app.import |
/assets/vendor-cda82a2f026df88e5960e5fb6b88849e.css |
To change these paths, specify the outputPaths
config option in ember-cli-build.js
. The default setting is shown here:
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp({
outputPaths: {
app: {
html: 'index.html',
css: {
'app': '/assets/application-name.css'
},
js: '/assets/application-name.js'
},
vendor: {
css: '/assets/vendor-cda82a2f026df88e5960e5fb6b88849e.css',
js: '/assets/vendor-537734ed4a55f6509f3f8aa6d17afb80.js'
}
}
});
//...
return app.toTree();
};
You may edit any of these output paths, but make sure to update the paths specified in your
app.outputPaths.app.html
default it is index.html
, and tests/index.html
. If this is not done,
your app will not be served with correct asset names.
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp({
outputPaths: {
app: {
js: '/assets/main.js'
}
}
});
//...
return app.toTree();
};
The outputPaths.app.css
option uses a key-value relationship. The key is
the input file and the value is the output location. Note that we do not
include the extension for the input path, because each preprocessor has a
different extension.
When using CSS preprocessing, only the app/styles/app.scss
(or .less
etc)
is compiled. If you need to process multiple files, you must add another key:
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp({
outputPaths: {
app: {
css: {
'app': '/assets/application-name.css',
'themes/alpha': '/assets/themes/alpha.css'
}
}
}
});
//...
return app.toTree();
};
If you would like to specify the output path for a single file in the vendor
directory, you can do so by using app.import
.
module.exports = function (defaults) {
let app = new EmberApp({});
app.import('vendor/someWebWorker.js', { outputFile: 'assets/someWebWorker.js' })
})
Now the asset will be available at an expected path e.g. localhost:4200/assets/someWebWorker.js
enabling new Worker('assets/someWebWorker.js')
.
Integration
When using Ember inside another project, you may want to launch Ember only when
a specific route is accessed. If you're preloading the Ember JavaScript before
you access the route, you have to disable autoRun
:
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp({
autoRun: false
});
//...
return app.toTree();
};
To manually run Ember:
require("app-name/app")["default"].create({/* app settings */});
Subresource integrity
SRI calculation is done using the addon ember-cli-sri (which is included by default).
This plugin is used to generate SRI integrity for your applications. Subresource integrity is a security concept used to check JavaScript and stylesheets are loaded with the correct content when using a CDN.
Why
The reason to add this to your application is to protect against poisoned CDNs breaking JavaScript or CSS.
- JavaScript DDoS prevention
- The latest GitHub DDoS attack
- Protection against corrupted code on less trusted servers
Customize
To customize SRI generation see: ember-cli-sri