Enable FastBoot in your Ember app
11 November 2016
What is FastBoot and why should you use it?
FastBoot is the awesome add-on that adds server-side rendering to your Ember app. This will make users of your application see the content of your page before any of the javascript is downloaded. In other words, the "time to first tweet" of your app is greatly reduced, which is a big win where and when people have slow or unstable network connections.
Another advantage is that search engine crawlers will have an easier job indexing your site, which brings SEO benefits.
Furthermore, your site will be readable with Javascript disabled which is convenient for screen readers.
I recently went through the process of enabling the demo version of the Rock and Roll application to run in Fastboot. Below, I'm going to tell you about the challenges I encountered and how I overcame them in the hope that my journey will prove valuable when you do the same for your app.
Installing the add-on
FastBoot is a regular Ember add-on, so installing it is piece of cake:
1$ ember install ember-cli-fastboot
I could then run
1$ ember fastboot
from the project's directory and had the node server serving my application at port 3000. It's important to note that you should refresh your browser tab each time you make changes to your code as FastBoot doesn't (yet) auto-refresh the way ember server
does.
I then disabled JavaScript in my browser and then directed my browser to http://localhost:3000
.
Disabling JavaScript in Chrome is most easily done by expanding the context menu of Developer Tools and then clicking on Settings:
Mirage is disabled in FastBoot mode
My first obstacle turned out to be Mirage.
Mirage is a great tool for mocking server responses and even prototyping your Ember app. I used it in development, too, and it turned out that since it turns itself off when your app is running in FastBoot mode, the requests hitherto handled by Mirage now went out and were thus unhandled.
The fix here was to disable Mirage in development (and, in my case, production, too) and to make the requests against an actual API.
You also have to add the hosts that will serve your Ember app in FastBoot mode to a list called hostWhitelist in your app's configuration.
In my case, it contains the host I wanted to deploy it to and any localhost port:
Serving assets
When I restarted the ember fastboot
and looked at the server-rendered version of my app, I saw that the dynamic data was now correctly rendered on the page. However, it did not have any styling.
A quick glance at the documentation made me realize I needed to pass the serve-assets
option to the command so that it serves the css (and other asset) files:
1$ ember fastboot --serve-assets
document is not defined
So now the main page, with the list of bands rendered fine but when I selected one of the bands to have their songs displayed, I got the following error:
1Error while processing route: bands.band.songs document is not defined
Since Fastboot runs your Ember app in a node environment, not in the browser, document
is not present. In my case, I accessed document
(through jQuery) to set the document title, which does not work in FastBoot mode.
The user guide suggested to use ember-cli-document-title, a FastBoot compatible way to set document titles. So my next step was to install that add-on:
1$ ember install ember-cli-document-title
Armed with this great add-on, I only had to define a title (method) in the corresponding route:
Missing dynamic content
The next thing that did not work was that the songs for a specific band did not load in FastBoot mode, the list of songs was empty each time.
Adolfo Builes and Jonathan Jackson helped me out by pointing out that songs are loaded asynchronously. The request to fetch the songs was only fired when the template rendered each song belonging to the band. FastBoot does not know when the page is fully rendered and thus relies on the beforeModel
, model
and afterModel
route hooks having finished their work. When that happened, the songs were not yet fetched and rendered on the screen yet:
The way to fix this was to block rendering in the afterModel
hook, by returning a promise that fetched the songs:
As you can see, I only pre-fetch the songs in FastBoot mode. In the browser, I let rendering start earlier, with a "pop-in" effect (which can be remedied in several ways in the browser, too).
The songs now appeared in the FastBoot "view" of the app, too:
You can read more about this in the "Use Model Hooks to Defer Rendering" section of the guide.
Fastboot-enabled hosting
It's fine to have FastBoot working in development but nobody actually needs it to work in that environment. It has to work when deployed to a server.
The guide has a whole page on deployment, listing several deployment options, from which I chose Heroku as it seemed the easiest option. And it really was.
All I had to do was to set the buildpack URL from my project:
1$ heroku buildpacks:set https://codon-buildpacks.s3.amazonaws.com/buildpacks/heroku/emberjs.tgz -a rarwe-demo
I then added a static.json
file to the root of my project, to disable forcing https requests, as the domain is not (yet) SSL-supported:
1// static.json 2{ 3 "root": "dist/", 4 "https_only": false, 5 "clean_urls": true, 6 "routes": { 7 "/**": "index.html" 8 }, 9 "headers": { 10 "/**": { 11 "Cache-Control": "private, no-store, no-cache, must-revalidate, proxy-revalidate", 12 "Pragma": "no-cache", 13 "Expires": "Sat, 05 Nov 1955 00:00:00 PST", 14 "Strict-Transport-Security": "max-age=31536000; includeSubDomains;", 15 "X-Download-Options": "noopen", 16 "X-Content-Type-Options": "nosniff", 17 "X-Frame-Options": "SAMEORIGIN", 18 "X-XSS-Protection": "1; mode=block" 19 }, 20 "/assets/**": { "Cache-Control": "public, max-age=512000" }, 21 "/robots.txt": { "Cache-Control": "public, max-age=512000" }, 22 "/crossdomain.xml": { "Cache-Control": "public, max-age=512000" } 23 } 24}
This step is really only needed to change the default https_only
setting. If you have SSL set up for your domain, you don't need the static.json
file.
The next time I pushed to the remote set up by Heroku, it just worked, and my app was now FastBoot enabled. Hooray!
Acknowledgements and further resources
I would like to thank Adolfo and Jonathan for their help in pointing me at Ember Weekend, an Ember app that runs in FastBoot and whose source code is publicly available, and also for overcoming the above mentioned "missing dynamic content" problem.
My app does not use many of Fastboot's features. If you're looking to see a more complex use case, check out the Ember Weekend source code.
If you want to learn more about FastBoot's architecture and rationale, I recommend checking out Tom Dale's great presentation he gave at Global Ember Meetup.
Finally, the Rock and Roll demo app that this post describes is available on Github at balinterdi/rarwe-demo and deployed to http://demo.rockandrollwithemberjs.com.
Share on Twitter