Ember Engines - Tips

Welcome to another post about Ember Engines! It’s been at least nine months since we’ve moved our Ember app to an engine (there’s a pregnancy joke in here somewhere…) and I feel as though I have a few things that’d be helpful to share with fellow Embereños. My coworker, Todd Jordan, from the Ember learning team gave a fantastic talk at Ember Conf 2017 on how we manage our engines. Go check his video out — it is jammed pack with great info! The point of this post is to touch on a few key points for quick consumption if you don’t have time to watch the entire video and also roll in some of my opinions.

Set Up Dedicated Chat Channels

Go setup a Slack channel if you don’t have one already. You won’t regret it. Communication is 🔑, especially as you add more engines and internal add-ons/dependencies. Even if your team is really small to start with, it’ll be helpful to have very focused rooms. Can’t or don’t want to use Slack? There are plenty of other options.

The Ember Community Slack has a great format. It’s easy to get help when you need it. Some channels are very clean and reserved for important announcements, while others are used for getting help. I recommend taking a page from their book and having a few different channels:

  • Announcements  — This should be used for announcing major changes. Examples are publishing newer versions of shared add-ons/dependencies, upgrading the host app’s Ember version in a branch, and similar “I-may-break-stuff” chats. Try to keep this channel clean so that important messages aren’t drowned out/ignored.
  • Help  — This channel can be used to ask and answer questions. There are going to be growing pains while you and your team figure things out. Especially as the number of engines/add-ons you support grows over time. Allow folks to ask questions, send links to PRs for additional eyes, ask for troubleshooting help when tests pass with Phantom locally, but not on the build server, etc. and keep the off-topic convos to a minimum.
  • Specific Engine or Addon Channels — Depending on how many engines/add-ons you have, you may find it helpful to have a separate channel for specific questions. If you’re a smaller group and just starting out, this may be overkill.
  • Off Topic — This channel is the fun one. Bonding with your fellow Emberños by chatting about Game of Thrones, discussing how a new version of node.js just released, and GIFs are all acceptable here (and recommended).

Dependency Sharing

Use semantic versioning where you can, but keep Ember and Ember Data pinned (or use the ~). The reason for this is so you know exactly which version of Ember you are on. A case where this broke us (if we had used the caret) is with Ember 2.12 — issue posted here, where our engines lost their styling due to treeForAddon not being called. More on Ember upgrades in a bit…

Semantic versioning of our engines in our host app package.json has worked very well, as long as you are mindful of breaking changes. Using the ^ allows us to automatically pull in minor changes (feature updates, for example) and bug fixes. This is great, especially for internal dependencies such as your engines and add-ons. External dependencies should be treated the same way until they give you a reason to pin versions (or use the ~).

/** host app package.json */
// ...other package.json info here...
  "dependencies": {
    "engine-a": "^2.0.0",
    "engine-b": "^6.3.0"

Making a potentially breaking change? Post it in one of the channels mentioned above. It’s better to just bump the major version than to make a potentially breaking change on other people’s builds. Once again, communication is key here!

Ember Upgrades

When it’s time to upgrade Ember versions, use the trusty announcements channel mentioned above to declare the intent of the upgrade. In my opinion, the host application should create a branch with the upgrade first. Engines can then run their upgrade branch linked (npm or yarn) to the upgrade host branch. This has been really smooth for us.

A super helpful add-on is ember-try. It allows you to run your tests against different dependencies. You can run against the latest version of Ember and Ember Data. It’s as simple as setting up a scenario and declaring which versions to use. You can even test against canary and beta builds!

Leverage Yarn for the Host App

Use a yarn lock file in your host app when gearing up for a release to production. Straight from yarn’s page:

In order to get consistent installs across machines, Yarn needs more information than the dependencies you configure in your package.json. Yarn needs to store exactly which versions of each dependency were installed.

This is helpful because it’ll ensure that the dependencies on your local machine match the dependencies when you go to package up your app on the build server, for example. This isn’t required, but definitely nice to have in my opinion.

Have a Good Deployment Plan

Having a good deployment plan for your engines is important so that you have version control. We have a pipeline that pulls down the engine, runs our unit, integration, and acceptance tests, and then deploys the “release candidate” (engine +host app) out to one of our development environments. We have automation tests that are written by our testing department that then run against the packaged app. These automation tests are the final stamp of approval. If all passes, we bump the version (or respect a version change in the package json) and then push the engine to artifactory to be consumed by the host app for realz.

Now, you may not need something this involved. Just ensure you have thought out how to manage all of your engines from a deployment standpoint! The goal being to respect semantic versioning and not introduce regressions.

Until next time…

I hope these tips were helpful! What tips would you share after working with engines for some time? I’ll be sure to update this page as things change. As always, thanks for the read and hit the recommend button if you enjoyed this post. Cheers 🍻!