Get Rewarded! We will reward you with up to €50 credit on your account for every tutorial that you write and we publish!

Creating a simple version notifier for Single Page Applications

profile picture
Author
Thomas Schäfer
Published
2021-09-08
Time to read
7 minutes reading time

About the author- My life for Aiur

Introduction

In this tutorial, I solve the problem that users use an old version of your web app. This might happen, because they don't realize a new version of your app was released. I introduce a simple way to notify users based on the npm package version. A React app will be used as an example, but at the end of the tutorial, you should be able to use the principles with any npm-based Single Page Application.

Prerequisites

  • Basic JavaScript/ReactJS knowledge
  • Basic npm knowledge
  • Tiny bit of bash knowledge
  • npm and git

Step 1 - Project setup

Note: You can also use an existing project that was set up with create-react-app and skip this step

In this first step, we set up the project with create-react-app. Running npx create-react-app version-check-example --use-npm will create a folder version-check-example with all necessary React dependencies and npm configurations. It will also initialize a git repository, and an npm project.

Step 2 - Make the app version available to our app at runtime

Our source of truth for the version of our app is the "version" field in the package.json file. By default, it is "version": "0.1.0" and will be incremented while you are developing your app.

At build time, npm will inject an environment variable called $npm_package_version into the build process, which we sadly cannot use directly in our React app. To make the value of this variable available at run time, we create a .env file in the project folder and add the following line:

REACT_APP_VERSION=$npm_package_version

All variables starting with REACT_APP will be injected by webpack, so we can use it at run time like this:

const version = process.env.REACT_APP_VERSION

Step 3 - (Periodic) Version checking

In this step, we will create a script that can be periodically called to fetch the newest version from the server and compare it to the current client version.

First we will create a version file with a static version string. We can fetch this version in our app to compare it to the client side version. We will generate this file in the next step. For now, just create a file named version in the public directory and add the following content (the current version):

0.1.0

Important Do not add a new line or any spaces to this file. It should exactly contain the version.

Next, create a file called version-check.js in the src/utils directory, with the following content:

// fetch current app version from the server and return it as a string
const fetchVersion = async () => {
  const response = await fetch('/version')
  if (!response.ok) {
    throw new Error('Error fetching version')
  }
  return response.text()
}

export const checkForNewVersion = async () => {
  // fetch version from server
  let serverVersion
  try {
    serverVersion = await fetchVersion()
  } catch (error) {
    console.error(error)
    return
  }
  // compare server version to running version
  // you can add your own logic to test if the client version is actually older than the client version
  // to prevent problems when your /version endpoint delivers an old version by mistake (e.g. when it is cached)
  if (process.env.REACT_APP_VERSION === serverVersion) {
    return
  }
  // show alert
  window.alert('A new app version is available. Please reload the page.')
}

Note: create-react-app automatically serves files from the public folder. That's why we can just load the version file with fetch('/version). You might have to make adjustment for your production build. You can read more about this here.

The function checkForNewVersion can now be called periodically anywhere in your app, e.g. in the src/App.js file:

import React, { useEffect } from 'react'
import checkForNewVersion from './utils/checkForNewVersion'

export const App = () => {
  // when component mounts, set an interval that checks for a new version every 5 minutes
  useEffect(() => {
    const interval = setInterval(checkForNewVersion, 5 * 60 * 1000) // check every 5 minutes
    // clear interval when component unmounts
    return () => clearInterval(interval)
  }, [])

  return (
    <div>...</div>
  )
}

If you now run the app with npm run start and change the content of the public/version file to 0.1.1, an alert should show 5 minutes after opening the app.

Step 4 - Generate version file based on package version

npm allows us to manage our package version. You can bump the version by using

  • npm version major
  • npm version minor
  • npm version patch

which will update the version in the package.json according to the semantic versioning rules.

Whenever npm version runs, some scripts that you can specify in your package.json file will also be executed in the following order:

  • preversion
  • version
  • postversion

We now create a bash script, which will read the $npm_package_version environment variable and write it to the public/version file. The script is located in the scripts directory and is called version.sh

echo -n $npm_package_version > public/version
git add public/version
  • The first line writes the value of the $npm_package_version environment variable to the public/version file.
  • The second line adds the changed file to git, so that it will be included in the git tag created by npm

After that, we add the following line to the "scripts" section of our package.json:

"version": "bash ./scripts/version.sh"

Note: You might need to make the version.sh file executable, e.g. by running chmod +x scripts/version.sh

Step 5 - Test

Run npm version patch in your command line. This should update the "version" field in your package.json (and package-lock.json) from 0.1.0 to 0.1.1. The content of the file public/version should now also be 0.1.1.

If you run git log in your command line, there should be an entry looking something like this:

commit your-commit-hash (HEAD -> master, tag: v0.1.1)
...

Conclusion

We achieved to create an automatic process that notifies users when a new app version is available. Whenever we update the version of the app with npm version [major/minor/patch], a script will run, that automatically updates the version file, adds it to git and creates a git tag.

The app periodically fetches the version endpoint and compares it to the version that is currently running in the browser. If the version changed, we can notify the user and tell him to reload the page.

License: MIT
Want to contribute?

Get Rewarded: Get up to €50 in credit! Be a part of the community and contribute. Do it for the money. Do it for the bragging rights. And do it to teach others!

Report Issue

Discover our

Dedicated Servers

Configure your dream server. Top performance with an excellent connection at an unbeatable price!

Want to contribute?

Get Rewarded: Get up to €50 credit on your account for every tutorial you write and we publish!

Find out more