It’s a good idea to have exact version information accessible from within any app you’re building, and it’s easy to put it there with modern tools. Join me for a quick dive through the layers that exist between git
and production in a conventional Dockerized React app.
Why Show Version Information?
There are a bunch of questions that a user-visible version number can help you answer:
- Did that deploy you’re waiting on percolate all the way through yet?
- Is the very latest build making it to your browser, or are you getting an old cached version?
- You’re on the phone with somebody reporting an issue. Are they getting the latest version?
- Is that bugfix on production yet? Is it deployed to dev?
The most important information you can provide is the specific Git commit. Additionally, you might want to include a build date and possibly a version number, if your project maintains one.
Adding Version Information with React & Docker
Starting from the top, I like to display a web app’s version information three different ways:
- User-visible text in the app
- In the JavaScript console
- Within `index.html`
1. React
So how do we get this information into React at build time? Environment variables!
We’re using Create React App (CRA), which automatically makes available any build-time environment variables beginning with REACT_APP_
. If you’re not using CRA, you can assemble something similar with Webpack’s DefinePlugin.
Here’s an example React component that displays the contents of the REACT_APP_VERSION_INFO
environment variable and logs it to the JavaScript console:
import React from "react";
export const VersionInfo: React.FC = () => {
const info = process.env.REACT_APP_VERSION_INFO;
if (!info) {
console.info("No version information present at build time.");
return <></>;
}
console.info(`version: ${info}`);
return <div>{info}</div>;
};
CRA also makes it easy to place environment variables in HTML:
<meta name="version-info" content="%REACT_APP_VERSION_INFO%" />
I think of this as a backup, in case something goes wrong and prevents execution from getting to the other points in the app where the version is displayed. It’s also easily wget-able.
So now we have an arbitrary string built into our app. You can test that it’s working by setting the environment variable locally and running your app as usual. But how do we get it into our deployed builds?
2. Docker
I’ll assume you’re deploying with Docker (i.e., you have a Dockerfile with a yarn build
command in it). We can plumb a new value through our Docker build by combining the ARG
command (which declares a build-time input) with the ENV
command to declare an environment variable:
# Dockerfile
ARG version_info
ENV REACT_APP_VERSION_INFO=${version_info}
3. Deriving the Information
Finally, we need to provide the version string to docker build
. On my project, we’re building and publishing Docker images from CI. Here’s an example shell script that combines the date with the commit to produce a version string like 20200826000247-6a82e57
:
commit=$(git rev-parse --short HEAD)
date=$(date '+%Y%m%d%H%M%S')
version_info="$date-$commit"
docker build -f docker/Dockerfile -t "$image_name:$commit" --build-arg "version_info=$version_info" .
Voila! Version information baked right into your app.
That’s It!
This doesn’t take long at all. Do it now, and you’ll be glad the next time you don’t have to dig through logs to figure out what version of your app is currently deployed. Years later, you’ll be really glad when you’re handling a support request for this old project that you don’t remember at all; you’ll thank your former self for their wisdom and foresight.
I blogged about a similar process with Ember and Heroku a few years ago. It’s fascinating how different this new process is.