Busting SPA Chunk Cache for Active Users After a Deploy

How we used Pusher to reload the user’s browser without them noticing it

Dobromir Hristov
Hypefactors
4 min readMay 4, 2018

--

It’s a common problem with single page apps (SPA): when a deployment finishes successfully after the user has loaded the app, they still use the old and cached version until they refresh the website.

This problem aggravates with async chunks. The app is split in parts and each part is only loaded on demand, like when a user navigates to a respective section. The user might be in one part of the app while a deploy process succeeds, then if they navigate to another part, the chunks they request will have been removed from the server by the build script. Problem: this causes loading errors.

We had the same issues with Hypefactors and Hype.News. Until we devised an elegant, yet simple solution to this problem.

Pusher is the main ingredient to this solution.

On a successful deployment, the CI pushes an event to notify the frontend. There we catch and queue a page refresh. When the user starts browsing the website again, the first navigation is via a page redirect. We also guard pages where a refresh might cause loosing important page state.

This approach is technology-agnostic. At Hypefactors, we use Vue, but this solutions works equally well for React or other frameworks. And for the deploy event notification any push framework can be used. We went with Pusher because its easy to use and reliable. There is a free to try, and totally worth it. For deployments we use Netlify. It’s fast, easy to use with an integrated CDN, prerendering and so on.

Enough talk, lets see how its done.

Prerequisites

First you need to register the needed app environments on Pusher. We chose to use separate pusher environments for each of our staging processes as opposed to using one for all environments. Inside each environment we created a public deployments channel.

Using one Pusher environment would require constant checking to make sure you don’t start refreshing the production app.

Setting up the Frontend

Create a notify-deployment.js and paste the code bellow, filling in the noted places.

Now every time you want to notify the frontend that a deploy was successful you do node path/to/notify-deployment.js production

Create a PusherService.js file that you can import at the bootstrap of your app.

The tricky part here is to find a way to pass different pusher keys depending on the current environment (dev/staging/production). We import different config files based on the currently set NODE_ENV

Import the right environment variables

Then we pass the variables to the app via the Webpack DefinePlugin plugin.

Pass the variables to webpack.DefinePlugin

Webpack will just replace process.env.YOUR_VARIABLE with the same variable inside the config folder.

You can use this method to get access to other environment specific keys, urls and others you defined via process.env.YOUR_VARIABLE

Now when your app loads, you need to subscribe to the development channel on Pusher. We use Vue so we do this in the App’s created hook.

Now this saves a FORCE_RELOAD variable into localStorage via the persist helper we have. This gives us an easy way to reload the user’s browser when they navigate around the app. We do this using Vue router’s beforeEach hook.

We check whether FORCE_LOAD is saved in localStorage and whether it is true. We use our load helper for that, which defaults to false if not set.

Next we check the route. If any of the parent matched routes is blacklisted, a.k.a. protected, it should not get refreshed, as precious form data might get lost. That means it will just wait for the next navigation event.

Finally we save FORCE_RELOAD as false and we navigate to the location we wanted via a full page refresh.

Set up the Deployment Script

All we need to do now is, after a successful deployment, we run the node notify-deployment --development

This will send an event to the deployment channel that you want to silently reload.

Plugging in the deployment script into Netlify

We have helper commands in package.json to make this easier to read and manage.

Helper commands for notifications inside package.json

That’s all folks!

This approach of reloading is great for continuous deployment, especially when you deploy multiple times an hour.

The code and scripts have been collected in a gist for easy copy pasting. Check out https://gist.github.com/dobromir-hristov/50df8fbdf52de942ee70552646e2eeb7

p.s. did you know that Hypefactors is hiring?

--

--

Dobromir Hristov
Hypefactors

I am a JavaScript developer with a passion for tech.