Ember-cli fingerprinting and dynamic assets

When we are building our Ember application sooner or later, we will have to deploy it to production. One of the issues that might arise will be related to assets.

Application on production without fingerprinted assets (e.g. for every deployment you generate a unique path for every static file) is locked into a cache of your user and force you to wait until user cache is cleared or expired.

Ember-cli, thanks to broccoli-asset-rev, have a good solution — just enable fingerprinting in config:

As you’ve probably noticed, we’ve added generateAssetMap: true, that instructs broccoli-asset-rev to generate assetMap.json in assets/ directory.

This file will have original asset file name and its fingerprinted equivalent, something like:

Everything looks nice — where is a problem?

The problem will arise soon, as we will generate the name of the asset dynamically. Broccoli is matching what we have in assetMap on the left side and replace it with what’s on the right side. If for example, we’ve generated image as computed property:

Now, we don’t have the ability to match it as static name, as `skin` can have any value, what do to? We have several options:

Solution #1 (simplest one)

This is the most straightforward and simple solution you might get and I suggest to go with it if it is possible and you don’t have a lot of dynamic assets.

As simple, as you can get — make a path to your asset static.

If you think, that this solution might not suit you, let’s continue.

Solution #2 (not a silver bullet)

If you have a lot of assets, for example, you have flags of countries and you need to match them dynamically. First, if you are not lazy enough — try implement Solution #1. If not, let’s get back to assetMap.json file that we’ve seen previously.

Knowing, that assetMap.json resolves all static files to fingerprinted equivalent, we can try to load it before application starts and create a custom service to resolve it. For that, we should create initializers/asset-map.js and services/asset-map.js.

This solution will load assetMap.json before application loads and will populate assetMap service with mapped values. This gives us ability to inject asset-map service in any place where we need it to resolve our asset.

One caveat with this solution — assetMap.json will be cached in the client browser. If you can avoid storing that file in CDN and/or you can setup it to avoid caching (eg. send headers for no cache), then this solution might work for you. If not, let’s see, what else we can do

Solution #3

Fingerprint assetMap.json and inject it into your app.

If we combine all previous solutions and fingerprinting of assetMap.json, we will have promising results. The finished solution ended up in the ember addon — RuslanZavacky/ember-cli-ifa.

Addon provides with automatic injection of assetMap-HASH.json into your application. Also it provides with initializer, service, and helper to get a reference in your app to the fingerprinted assets.

Simply enable it in your environment.js as

ifa: { enabled: true }

and configure fingerprint block in your ember-cli-build.js

fingerprint: {
enabled: EmberApp.env() === 'production',
prepend: '', // can be a link to your CDN
generateAssetMap: true,
fingerprintAssetMap: true
},

I hope it helps and all feedback is warmly welcomed!