Caching in a Vue.js PWA
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
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 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 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
Page Build 2
usesservice worker Build 2
✅- Refresh, Reopen
Page Build 2
usesservice worker Build 3
⚠️ (probably ✅)- Refresh, Reopen
Page Build 3
usesservice 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.