Automagic reload for clients after deploy with Angular 4 (updated to work with Angular 7)
Most of the webpages I’ve built run around the idea that people come, do their things and then go away. This process is repeated for every time they need the functionalities provided by the site, be it an investment platform, e-shop or some sort of an administration tool.
But what if the users don’t leave, ever? What if they keep the page open 24/7, without refreshing, re-logging or re-entering the site. Imagine monitoring computers at factories or at big storage houses. They have separate machines just for this one thing that will be kept on the page forever as this single page is the sole purpose of the computer.
Apart from all kinds of other issues or problems this may arise, one that we are going to talk about today is this: ‘How can we be sure the users use the latest version of the site?”
A trick often used, is to have your files timestamped each time you change them. This will force browsers to invalidate the cache and re-download the files, and thus all the people who come to the site after deploy will get the new version of your files. There will always be users who have left the page open and will be using the old version for a short time, but usually this isn’t a big problem, especially when dealing with sites where users spend 2–10 minutes.
But in our case, we deal with users who will theoretically never reload the index.html, so even if the timestamps or hashes of the files change, they’ll never know about it.
So what are going to do about?:
- We’ll hash our file names each build so we know when they have changed
- We’ll create version.json in our dist folder which holds the current build hash and also enter the current build hash into the code itself.
- We’ll make frontend poll the version.json every X minutes to check if the hash has changed compared to it’s “inner” hash.
- If it has, we’ll reload the client either forcefully or gracefully by giving a pop-up / other kind of notification about the new version.
Note that even though in this post we’ll do it for Angular 4, it is not in any way locked to Angular or any of its specific versions and can be achieved in all SPA’s.
When building Angular 4 project with angular-cli and production flag, it will hash the files automatically so the first part is covered by their default webpack configuration. All you need to do is: ng build --prod
and you’ll get bunch of files in your /dist/
folder, one of them being /dist/main.somehash.bundle.js
. This is the file we care about as this holds all of our own JS. There are bunch of other files too that get generated during the build process, but we’ll focus on the main.js.
For the second point, I’ve created a /build/post-build.js
file:
This file is run after angular build, so our production build command currently looks something like this npm build && npm run build --prod && npm run post-build
post-build is just a script in our package.json:"post-build": "node ./build/post-build.js"
After running this script, you should have version.json in the /dist/
folder with something like:
And the third & fourth part go together, so we’ll have a version-check.service.ts
which handles the logic of polling and forcing the client update.
This is imported in the app.components.ts
and in the ngOnInit
we call theversionCheckService.initVersionCheck(environment.versionCheckURL);
That’s it. Now, whenever you do a deploy, the hash will change in the version.json and users will be notified after they have polled the version file. You can have the polling interval smaller if it is critical that all the users run the latest version, or longer if it’s not. You could also include bunch of other information into the version.json if you need to, for an example, to control if this deploy is critical or not and change between forceful and graceful refresh using that information.