Introducing ember-cli-server-variables add-on

Posted on

As I’ve mentioned in previous posts, we’re working on migrating over our global Ember application to Ember CLI. One of the big changes we are making as part of this migration is how our index.html file is built and deployed.

Background

We use ExpressJS to serve up our application. Today, our Express server generates the index.html file, embedding some request-specific data in the page payload to be read in by the Ember application. For instance, we use Node GeoIP to determine the user’s physical location.

Because Ember CLI generates an index.html file with the ember build command, and ember-deploy saves this file off to Redis, we needed to come up with a way to not build the index.html file on our application server at request-time.

I briefly touched on our plans to use ember-cli-deploy to improve our deployment system. Pending support for a configuration-only deploy, we will need to modify the index.html page using a library like CheerioJS in our Express server before we send the content down to the user.

ember-cli-server-variables

In order to simplify this process in production and dev environments, I wrote an Ember CLI add-on called ember-cli-server-variables that makes adding and reading meta tag configuration variables a breeze. Check out the project’s README for the latest information on how to install and configure it.

How it Works

Ever noticed the {{content-for}} helpers in the stock Ember CLI index.html file? The Ember CLI add-on environment allows add-ons to implement a contentFor function in the index.js file that outputs the returned string directly into the page. In our case, it’s super handy because we need to write out meta tags into the head of the file that contain request-specific information.

All you have to do is place a {{content-for 'server-variables'}} helper in your index.html file provide an array of variables you’d like added to the page. The add-on does everything else to get those meta variables into the head tag. You can also provide sane defaults for development mode, when your app server won’t be running to fill in the variables.

Example

After adding the {{content-for 'server-variables'}} helper, edit your environment.js file with a list of the variables you want added and (optionally) with defaults for development.

var ENV = {
  ...

  serverVariables: {
    tagPrefix: 'prefix',
    vars: ['token', 'location']
  }
};

if (environment === 'development') {
  ENV.serverVariables.defaults = {
    token: 'example',
    location: 'Denver'
  };
}

To confirm it’s working, fire up development server ember s and check out the head tag. You’ll notice two new meta tags:

<meta name="prefix-token" content="example">
<meta name="prefix-location" content="Denver">

Now that you’re all setup, you can use the convenience service implemented by the add-on to fetch the property.

MyController = Ember.Controller.extend({
  serverVariablesService: Ember.inject.service('serverVariables'),
  userLocation: Ember.computed.reads('serverVariablesService.location')
});

Great, everything is working in development now. Now the last task is to modify your application server to find the tag and replace it with the appropriate content for each request. This add-on doesn’t care how you implement things on your app server, but good choices include modifying the tags with a library like CheerioJS or using string manipulation.

Again, this step will be made easier once we figure out the configuration-only deploy with ember-cli-deploy because we will be able to construct the index.html page on the app server again.

Developing an Add-On

This was a great chance to learn about how to develop an add-on. As is common with Ember CLI, there was an obvious way to get started and opinions in place about how to structure the app. If you’re about to jump into writing your own add-on, definitely read the docs to get started. Additionally, check out Brian Cardarella’s tips for writing add-ons post for some tips and tricks.

Conclusion

I hope that this write-up and add-on can be of use to others who need request-specific data available to their applications. The add-on is pretty basic now, but I’m interested to see if there are others who have ideas on how to make the add-on more robust to cover all use-cases.

If this library is useful to you, please make sure to star the project and file issues if you find any.

Find an issue?
Open a pull request against my blog on GitHub.
Ben Limmer