update-available

Since the first release of Cushion, we’ve had an “Update Available” alert appear when we push a new version. It slides down from the top of the page and lets users click to see what’s new. This alert serves two purposes—1) it keeps the user informed of updates while making it clear that we’re consistently updating Cushion, and 2) it refreshes the page to ensure the user is on the most up-to-date front-end. In this post, I’m going to explain how the alert works, point out a few hurdles, and list a few ways we can improve it.

Long story short, the alert uses an environment variable and a response header to tell the front-end that there’s an update. The env var represents the version number and gets injected into a <meta> tag for the front-end to read. Since Cushion is a single page app, once it’s loaded, the page isn’t refreshed unless the user refreshes it. Because of this, Cushion knows which version it’s currently using because of that <meta> tag.

Cushion relies heavily on API endpoints, which might serve a newer version of the backend if a release is deployed since the user last refreshed the page. To know whether or not this is the case, we return the env var version number as a response header, X-APP-VERSION. Then, on the front-end, we simply check whether the response header version differs from the version we have stored in the <meta> tag. If it does, show the “Update Available” alert. If not, carry on.

The alert itself has two options—click to close or see what’s new. If the user clicks to close the alert, the page refreshes and loads the latest front-end code along with the updated version number. If the user wants to see what’s new, we open the changelog in a new tab while refreshing the app in the background. This sounds easy, but Safari makes it tricky (of course).

The “See what’s new...” text is a basic <a> tag that points to the changelog URL. We also listen for a click event that triggers the reload. This works in every browser except Safari, which doesn’t open the changelog in a new tab—it only refreshes the app. I assume Safari triggers the href after the triggering the click event, but we’re able to get around this by simply delaying the refresh by 100ms with a setTimeout.

In the first iteration of the update alert, we set the version number at the tail end of our deploy process. This wasn’t ideal because it would cause an additional restart of our servers. When we simplified our build process earlier this year, we took this opportunity to improve this step. I discovered that Heroku has a dyno metadata feature that exposes the server’s slug version as an env var. This let us cut that last step out of our deploy process and use the automatically-populated Heroku env var instead.

This is where we currently are, but there are still ways we can improve. For one, the downside of using the Heroku env var is that the slug version increments even when updating environment variables. If we were to set an env var ahead of deploying, Cushion would tell users that there’s an update available before the deploy started, which isn’t ideal. We’re able to get around this by updating env vars during the preboot phase, but still, not ideal. To improve this even further, I’d love to establish a flag that only tells Cushion to alert users when the front-end code changes. This would let us make backend changes without bothering people, in case the “Update Available” alert becomes too much.