Deployment

Staging Deploys with ember-cli-deploy

Michael Klein

· 7 min read

When deploying your Ember.js applications with ember-cli-deploy, working with staging environments can be unintuitive. To do this cleanly you should not think of staging as an environment but in terms of a deploy-target you deploy your application to with a customized configuration. This post shows you how to do this properly.

Setting up staging deploys with ember-cli-deploy can be unintuitive because the default configuration of ember-cli configures your application based on environments. This post will show you the right way to setup staging deploys with ember-cli-deploy and explain the benefits of customizing your deploy workflow around the idea of deploy-targets instead of environments.

This blog post is based on a post that I wrote on my old blog over four years ago. The patterns discussed still apply as well as they did back then and I want to make sure the best practice around Ember.js staging deployments stay well documented even when I take my old blog offline.

ember-cli-deploy is the recommended and community agreed-upon way to deploy your Ember.js applications. It comes with a lot of plugins that enable you to customize your deployments and is one of the top-rated ember-cli-addons on emberobserver .

Here’s a great video of @lukemelia and @grandazz explaining the idea behind ember-cli-deploy's deployment pipeline in great detail.

To put a long story short, you should be using ember-cli-deploy to deploy your ember-cli-applications to production.

Deploying to production for most teams is only half the story of their deployment workflow though. Most teams also deploy to a staging-environment, an environment that mirrors production as close as possible and is used to test new features internally before releasing new code to the public.

Kind of unfortunately ember-cli only supports three environments development, testing and production and does not know anything about staging-environments when running the ember build-command. In a way, this makes sense because staging is not a name for a pre-production-environment that all teams in the world agree on. Some teams name the pre-production-environment pre-production or qa, others simply need to support multiple staging-environments at once.

Despite no notion of staging, pre-production and similar as environments in ember-cli, you can still deploy these kinds of “environments” with ember-cli-deploy.

The difference between staging and production

Because staging is usually the last stage before a feature goes live into production, we want staging to mirror production as close as possible. This way we hope, before going live, to identify issues that would otherwise only show up after we released code to production.

staging will commonly be accessible via a different URL and will most likely use different hosts for your API-services and use different API-Keys for 3rd party services that you use in your application (error-tracking-, mapping-services, etc.), but other than that it should behave exactly the same as production.

This is important because this tells us that if we want to mirror what’s happening in production as close as possible, we don’t want to change the way our application is built but only change certain configuration settings of the application we deploy to staging. This is not what environments do in ember-cli though.

Environments are used by ember-cli to customize the application build in general. For example, when building for the production-environment ember-cli will minify your application code via ember-cli-terser , something that it won’t do for development and test by default.

After clarifying this, we now know what we want ember-cli-deploy to do when deploying to staging. We want it to create a production-like build but be able to change certain configuration parameters based on config/environment.js, and we also want to be able to deploy to a different location than we do when deploying to production.

So how do we get ember-cli-deploy to do the right thing for us? We need to do the following:

  1. instruct ember-cli-deploy to deploy to a different location than when deploying to production
  2. build the ember application mirroring the production-build
  3. use a different configuration from config/environment.js based on where we deploy to

Deploy Targets

When taking a closer look at the /config/deploy.js-configuration file that ember-cli-deploy creates for us when installing the addon, you see that ember-cli-deploy does not concern itself with environments, it names these different stages of deployments deployTargets instead.

As you might have figured out already, this is by design and not an accidental misnomer. environment refers to how the application should be built, deployTarget refers to what stage you want to deploy to. The deployTarget that you see referenced in ember-cli-deploy's deploy-configuration will be set based on the target for your deployment you pass to the ember deploy-command. Examples:

# deployTarget 'production'
ember deploy production

# deployTarget 'staging'
ember deploy staging

# deployTarget 'pre-production'
ember deploy pre-production

ember-cli-deploy uses the deployTarget to customize the deployment. For example, you can use the deployTarget to change to which bucket the index.html-file ember-cli-deploy-build built for you will be uploaded to by ember-cli-deploy-s3-index based on where you are deploying to:

Building your application

Before uploading your application assets somewhere, you first have to build your Ember.js application. When using ember-cli-deploy you will use the ember-cli-deploy-build -plugin to do that. The plugin does more of course, but to simplify a bit it will run the ember build-command that ember-cli provides for you at the right time in the deployment pipeline, passing whatever environment you have configured in config/deploy.js.

The most straight forward way to configure a staging-build is thus something like this:

Of course, as discussed in a previous section, this isn’t wrong technically but will lead to problems because you are telling ember-cli-deploy-build to build your application in the staging-environment. ember-cli does not know about other environments than development, test and production and nor do other addons that you include in your application. Addons that you are including can’t know about how your pre-production environments are called and won’t add their dependencies in a production-friendly way unless you build your application in the production-environment.

For example, ember-faker will add all its fake data to your staging-build which will bloat your application and won’t mirror your production-build as you’d want staging to do.

What we need to do for the build instead, is to use the production-environment to build the application:

But you still need to pass staging to the build command as this is used to build your application’s config/environment.js-file that will be included in the bootstrap index.html that you will serve to your users. Right?! No.

Changing environment.js

As it turns out it’s pretty easy to build a correct production-like staging-build because building your application is based on three files: config/deploy.js, config/environment.js and ember-cli-build.js.

  1. config/deploy.js - used to customize the deployment
  2. config/environment.js - used to customize configuration settings like API-URLs based on an environment
  3. ember-cli-build.js - contains the build specification for Broccoli. Used for customizing the build of your application (customize fingerprinting, manually including JS-dependencies etc.)

ember-cli will create the environment-configuration it includes in your app’s index.html based on the function exported in config/environment.js that gets passed the environment from the ember build-command.

As it turns out, creating a production-like-build with a different configuration from config/environment.js in index.html is pretty easy. You just have to change the checks for environment, that gets passed into the function in config/environment.js, from the passed-in environment to the DEPLOY_TARGET environment-variable that ember-cli-deploy will set for you when executing a deploy:

You can use the same idea when you need to customize settings based on the deploy-target in ember-cli-build.js - the DEPLOY_TARGET-environment-variable will be available there as well.

Summary

That’s all there is to it. A long post for an easy concept. When you need to configure your application based on where you are deploying to, use the DEPLOY_TARGET-environment-variable that ember-cli-deploy will setup for you when executing a deploy. Don’t change the build environment because for staging-deployments you want to mirror the production build and only change certain configurations of your application.

With this setup, you can deploy to multiple production-like deployTargets and customize their configurations and deployments quite easily.

Thanks to the ember-cli-deploy -team 👋 for a great deployment pipeline and @pangratz for valuable discussions on this topic 🍻.

ember-cli-deploy makes it easy to setup a deployment for your Ember.js application but sometimes teams have very complex requirements for their deployment pipelines. Don’t hesitate to if your team does. We are here to help your teams deliver ambitious applications to production - and staging 🙃 - with confidence.

If you have questions or want to share your thoughts about this post with me you can find me on Twitter - I’m always interested in hearing about your experiences with ember-cli-deploy and challenges you face when deploying your Ember.js apps.

Schedule a call

We are here to enable your team to deliver ambitious applications. Let's discuss how we can help.

European flag

© 2020 effective ember All rights reserved.