I recently set up previewing revisions with Ember CLI Deploy. There is no single best practice on how to do this yet, but here is how I did it.
This post assumes you use the ember-cli-deploy-revision-data plugin in conjunction with an index adapter (Redis, S3, SSH) for Ember CLI Deploy.
About revisions
Everytime you deploy index.html
with Ember CLI deploy, it gets tagged with a
revision. By default this is an MD5 hash of the index.html
file itself, but it
can also be a Git commit hash, or the version from your package.json
.
How exactly index.html
gets tagged depends on the index adapter. For example:
using the S3 adapter, the tag will be appended to the filename; using Redis, the
tag will be part of the key where the file is stored.
Once you have one or more revisions deployed to the target server, you can
activate one of the revisions, which will be the default index.html
the users of your app will see.
Viewing revisions without having to activate them
It would be very nice to be able preview a revision (maybe QA test) on the
production server, before you activate it and release it to the public. My idea
was to be able to do this by visiting
https://example.com/rev-a76df687f97e9ab8ca82d1a1/
.
It is really simple to set up your webserver to do this, so I won’t go into
that, but there is a caveat on the Ember side of this. If you navigate to the
revision, the router will throw an error: The route rev-a76df687f97e9ab8ca82d1a1/ was not found
.
What is happening? The Ember.Router
is not intelligent enough to know that you
meant to route after the /rev-a76df687f97e9ab8ca82d1a1/
portion of the path.
You have to explicitly configure the router to route on a path other than /
.
Fixing the router
Setting up the router to work from a base path should be fairly straightforward,
for example to route on /awesome-app/
you can set the
rootUrl
:
import Ember from 'ember';
const { Router } = Ember;
const Router = Router.extend({
location: 'auto',
rootURL: `/awesome-app/`
});
To route revisions is a little more complex, as you can’t just type in a simple
string and be done with it. To be able to handle revisions, you can make the
rootURL
a computed property instead:
import Ember from 'ember';
const {
Router,
computed,
isPresent
} = Ember;
const Router = Router.extend({
location: 'auto',
rootURL: computed(() => {
let path = window.location.pathname;
// Looks for /rev-a76df687f97e9ab8ca82d1a1/ at the beginning of the path
// Tweak this regex to match your own style of revisions.
let revisionMatch = new RegExp('^/(rev-[^/]+)').exec(path);
// If there was a revision at the beginning of the path
// return it as rootURL
if (revisionMatch && isPresent(revisionMatch[1])) {
return `/${revisionMatch[1]}/`;
} else {
return '/';
}
})
});
When the application loads, the rootURL
computed property will be executed once.
If the rev-*
part is in the path it will return that as the rootURL
, else it
will just return the default /
.
Caveat: baseURL is set in ENV
By default the baseURL
property in your config/environment.js
is /
and
does not interfere with the rootURL
in the router, but when it is something
like /awesome-app
, then you will run into trouble.
It is best to not use baseURL
in conjunction with rootURL
. If you have a base
path the app is served from, I would recommend you add it to the rootURL
.
Here is how I solved it:
import Ember from 'ember';
import config from './config/environment';
const {
Router,
computed,
isPresent
} = Ember;
const Router = Router.extend({
location: 'auto',
rootURL: computed(() => {
let baseRootURL = config.baseRootURL || ''; // NOTE: This is not baseURL
let path = window.location.pathname;
let revisionMatch = new RegExp(`^${baseRootURL}/(rev-[^/])`).exec(path);
if (revisionMatch && isPresent(revisionMatch[1])) {
return `${baseRootURL}/${revisionMatch[1]}/`;
} else {
return `${baseRootURL}/';
}
})
});
So now you know
If you have a backend that serves revisions on a scheme like
/rev-a76df687f97e9ab8ca82d1a1/
, then this is one way to set up your Ember app
to work with that scheme. Don’t forget to check your app’s baseUrl
.
If you figured out another way to set up something like this, then please share it!