Caching in a Vue.js PWA

Axel Hodler
4 min readMay 10, 2020

--

Photo by evandroanjos on Pixabay

A Progressive Web App (PWA) is a way to have native app (iOS, Android) like features, such as the ability to work offline or push notifications, on a web page. The Vue CLI offers a PWA plugin.

Using the PWA plugin there are issues where we are not seeing the latest build without having to hard-refresh the page or by opening it in incognito mode.

The PWA option might have been chosen during the generation of a project but left without any configuration.

We troubleshoot the issue. On the way we learn how Vue.js behaves with the plugin in general. It is helpful to create an example project to validate how things work.

If we don’t have them already we install the required dependencies.

npm install -g @vue/cli serve

Let’s generate a new project with vue-cli.

vue create pwa-test

Picking Manually select features and selecting the optional Progressive Web App (PWA) Support . It is the only thing we change. We keep the default settings for the other steps because we don’t really care about them.

We change into the directory, run the build and serve the app on localhost.

cd pwa-test
npm run build
serve dist

Upon visiting, in version v4.3.1 the Heading will state

First build without changing anything

Now we stop the serve dist and visit the browser again. Instead of Site can't be reached we are provided with the page. Nice, it got served from the cache. One of the benefits of a PWA.

We open our editor and change App.vue to state Welcome Build 2 instead of Welcome to Your Vue.js App

Again we build and serve the build.

npm run build
serve dist

Upon visiting the page on localhost it is still

The cached first build

The heading did not change to Welcome Build 2.

Why?

PWA default caching in action.

It does not matter how often we refresh the page. We will still see the above. What we need it as a hard refresh, ignoring the cache.

On macOS with Chrome it’s accomplished with Cmd + Shift + R.

The second build

The normal user probably does not know what a hard refresh or a cache is. In some cases they might not get the latest version for quite some time if we leave things as is.

Thus let’s change the code to provide the latest versions with soft refreshes F5 or Cmd + R , or by coming back to the page, too.

One simple solution is by creating, or extending, the vue.config.js . It should be located in the root of your directory. We use the following pwa settings

module.exports = {
pwa: {
workboxOptions: {
skipWaiting: true,
clientsClaim: true,
}
}
}

These settings can be found in the workbox documentation.

Having these settings will let the new service worker control the web page as soon as possible.

By default the service worker file will be auto-generated. It will use the settings chosen above. After a build we can find it in dist/service-worker.js containing the following extra lines

workbox.core.skipWaiting();workbox.core.clientsClaim();

The PWA plugin allows us to specify our own service-worker.js if we need to.

To test the new settings we change our Welcome Build 2 to Welcome Build 3

Again we run

npm run build
serve dist

On visiting the page we will see the old Welcome Build 2 again. But. If we reload, or close and reopen the tab, we get

Why did we not get it when we went there initially but only after the first reload?

If we check the console in the development tools we can see the following lines

App is being served from cache by a service worker. [...]
Service worker has been registered.
New content is downloading.
New content is available; please refresh.

These log statements are located in src/registerServiceWorker.js in our project. Thus if we want to change what happens after the updated event we can specify it there. The default console.log statement will only be read by developers though.

The log statements show that there is a time when the page of Build 2 is using the service worker of Build 3. If Build 2 has expectations of the service worker these need to be taken care of by the service worker of Build 3 too.

The flow is as follows

  1. Page Build 2 uses service worker Build 2
  2. Refresh, Reopen
  3. Page Build 2 uses service worker Build 3 ⚠️ (probably ✅)
  4. Refresh, Reopen
  5. Page Build 3 uses service worker Build 3

We could prompt the user with New content is available and offer a refresh button.

The PWA Plugin of VuePress accomplished that.

Under the hood the Refresh button uses location.reload(true) which is reloading the current page.

As if we were using the refresh button of our browser.

--

--

Axel Hodler

Building things. Usually by writing code. www.hodler.co. Software Engineering @porschedigital