Ember Fastboot

FastBoot allows Ember to be rendered on both a server and browser instead of only a browser. Ember is great after it’s downloaded however on first page load downloading and evaling javascript in the browser takes too long. FastBoot is the best of both worlds, you get a fast initial page load and fast interactions after loading.

ember-fastboot.com has a great tutorial on how to get started, so I’m going to focus on specific issues I ran into when trying to implement FastBoot.

Setting up the development environment

The development environment was the most frustrating part of working with FastBoot in my opinion. Currently, live reloading doesn’t work so any time I wanted to make a change I had to restart the FastBoot server. Also there’s no proxy option for ember fastboot so you need to add an adapter host.

Authentication

Authentication with FastBoot isn’t too hard, really. The main issue I ran into was realizing that FastBoot makes API calls too and consequently it needs auth headers. So, if you’re authenticating with a cookie, you need to pull the cookie off of the request to the FastBoot server and then send that along with future requests. The easiest way I found to do this is with an adapter header.

What to defer

By deafult FastBoot tries to call all of your model hooks and renders the page based on those hooks. So if you have a widget on your page that makes an AJAX call that isn’t in a model hook it’s not going to get called. There’s a function called deferRendering that can get around this which I haven’t used yet but it’s something to be aware of.

The shoebox

When you’re using FastBoot a lot of work is duplicated because the same code is used for both the server and client. For example, when your route makes an API call it happens in both FastBoot and on the client. The solution to this is the shoebox. The shoebox lets fastboot render your model’s JSON on index.html and load that into the store from the client. I recommend taking a look at ember-data-fastboot and adapting to your needs.

How to setup Ember Deploy

Recently I had a problem where I would have to deploy my Rails app to deploy my Ember app. I found that Ember Deploy was the solution. Ember Deploy is awesome, you should be using it if your deployment strategy is suboptimal.

Ember Deploy is the methodology that your assets should go somewhere and your index.html should go somewhere. The assets typically go on S3, and the index needs to be served by your server (due to CORS restrictions) but can go anywhere usually Redis. Ember deploy allows a lot of nifty things like preview URL’s, zero downtime and dynamically modifying index.html.

For my setup I decided to use ember-cli-deploy with a Redis and S3 adapter.

npm i ember-cli-deploy --save-dev
npm i ember-deploy-redis --save-dev
npm i ember-deploy-s3 --save-dev

ember-cli-deploy expects config/deploy.js to contain deployment settings that look like this

module.exports = {
  development: {
    buildEnv: 'development',
    store: {
      type: 'redis', // the default store is 'redis'
      host: 'localhost',
      port: 6379
    },
    assets: {
      type: 's3', // default asset-adapter is 's3'
      gzip: false,
      gzipExtensions: ['js', 'css', 'svg'],
      accessKeyId: '<your-access-key-goes-here>',
      secretAccessKey: process.env['AWS_ACCESS_KEY'],
      bucket: '<your-bucket-name>'
    }
  },

  staging: {
    buildEnv: 'staging',
    store: {
      host: 'staging-redis.example.com',
      port: 6379
    },
    assets: {
      accessKeyId: '<your-access-key-goes-here>',
      secretAccessKey: process.env['AWS_ACCESS_KEY'],
      bucket: '<your-bucket-name>'
    }
  },

   production: {
    store: {
      host: 'production-redis.example.com',
      port: 6379,
      password: '<your-redis-secret>'
    },
    assets: {
      accessKeyId: '<your-access-key-goes-here>',
      secretAccessKey: process.env['AWS_ACCESS_KEY'],
      bucket: '<your-bucket-name>'
    }
  }
};

I also specified a manifestSize which determines how many revisions Redis will keep. The only other thing I did was make some modifications to my Brocfile.js and config/environment.js to add the staging environment.

I used this gem for connecting to Redis. After that, I added a route to a controller that reads the contents of the current Redis key and sends that revision to the client. It looks something like this

class MyController
  class << self
    def redis
      @redis = Redis.new(url: 'redis://staging-redis.example.com');
    end
  end

  def index
    currentKey = redis.get('my-project:current')
    render text: redis.get(currentKey)
  end
end

Notice that my-project:current is acutally a link to the <current-revision> You can do a lot of other neat things here like take in a revision param and render that instead, or insert ruby generated content into your index.html.

After all of that is setup, the commands are easy:

  • ember deploy:list Lists all revisions

  • ember deploy Deploys assets to S3 and index to Redis

  • ember deploy:activate --revision=<revision> Moves a revision to current