Creating Progressive Web Apps with Vue

This post is 4 years old. (Or older!) Code samples may not work, screenshots may be missing and links could be broken. Although some of the content may be relevant please take it with a pinch of salt.

Progressive Web Applications are websites that act and feel like applications - they have features such as support for notification and they also work while there's no network connection.

Vue.js is an open-source JavaScript framework for building web-based applications.

This article will showcase how to create a Progressive Web Application (PWA) using Vue.js.

Note that this article was created by using the Vue CLI v 3.9.3. Older of future versions of the CLI may introduce some slight changes.

Please also note that this article does not cover the basics of Progressive Web Applications - readers should already be familiar with the basics of PWAs. If you'd like to learn more about them check out my book on the topic.

Create the Vue app

First and foremost we can use the Vue CLI to create an application by first executing npm i -g @vue/cli to install the CLI, and then vue create vue-pwa to create the application.

At the point the CLI asks us a few questions - we must choose "Manually select features" instead of a preset to proceed.

These were the items that I have selected - you can select something different, what matters, however, is that the PWA feature is selected:

Vue CLI v3.9.3
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, *PWA*, Linter
? Pick a linter / formatter config: Airbnb
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

If you open the source code for the project you'll notice that there's no service worker file, although there is a registerServiceWorker.js file present which does register a service worker based on the following condition:

if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready() {
console.log(
'App is being served from cache by a service worker.\n'
+ 'For more details, visit https://goo.gl/AFskqB',
);
},
// ... etc

This means that Vue only generates a service worker if we create a production build. Let's do this now by executing npm run build. (Alternatively, you can also do npm run serve --build)

Once the command has finished running, open up the resulting dist folder and note that a new file is present with the name of service-worker.js.

This is an automatically generated service worker, which under the hood uses Workbox (at the time of writing this article, it is using version 3.6.3 of Workbox, but the latest version of Workbox is 4.3.1. If you want, you can manually update this bearing in mind that after each rebuild this would get reset)

If you're new to Workbox I suggest you read about it here.

Precaching

Precaching is a concept where files - usually static assets that are required for an application to run - are downloaded ahead of time, before the Service Worker is installed, making these files immediately available for offline usage.

If you open up the file dist/precache-manifest.[hash].js you can see that all the files that make up the Vue app have been added with a revision and a URL. Workbox uses this information to place the files to the cache and by looking at the revision (which is just an md5 sum of the content of the file), it can tell whether the file has been updated or not - and, in turn, whether it needs to be updated in the cache or not.

Customising the service worker

Everything works well out of the box, but there could be some situations when we need to customise the service worker itself and adjust it to fit our needs. Let's take a look at how to customise the service worker for our Vue app.

Customisation is possible via vue.config.js and by utilising Workbox configuration options.

What can we configure exactly here? As mentioned earlier, there are two types of configuration that we can utilise - one is specific to Workbox, while the other one is specific to the Vue PWA plugin itself. Let's take a look at the latter first.

  • iconPaths: allows us to specify the locations for Android, Apple and Microsoft mobile icons since all of these devices have different requirements with regards to the dimension (the options are favicon16, favicon32, appleTouchIcon, maskIcon and msTileImage. They all have default values.

  • themeColor: specifies a hexadecimal colour value for the application when seen on a mobile interface.

Regarding the Workbox configuration options, we can use the following:

  • workboxPluginMode: this can either be set to GenerateSW or InjectManifest - more on this later.
  • workboxOptions: pass in additional options for Workbox

The entire list of options can be found on the npm page for the plugin.

GenerateSW vs InjectManifest

GenerateSW (which is, by the way, the default operation), will create a new service worker file whenever the app gets rebuilt.

InjectManifest on the other hand, allows us to start with an existing service worker, and the build script creates a copy of it with a "precache manifest" injected into it.

Depending on which method is used, we need to differentiate between options that we can provide Workbox.

GenerateSW

For GenerateSW we can specify options such as swDest (defaults to service-worker.js to specify the path and filename of the service worker file that is going to be created by the build process.

InjectManifest

For InjectManifest we can specify swDest (just like above) but also swSrc which should point to an already existing service worker file.

A sample service worker file

This is how an example service worker file would look like, which we could use in conjunction with InjectManifest:

if (workbox) {
console.log('Workbox loaded');
workbox.precaching.precacheAndRoute(self.__precacheManifest);
// additional service worker code
} else {
console.log('Error loading workbox');
}

Note that in the above self.__precacheManifest will refer to the file that gets generated by Vue automatically and it contains a list of assets as mentioned before.

The resulting service worker file (after the build) is going to have one extra line, which is responsible for importing the preacheManifest and Workbox itself:

importScripts(
'/precache-manifest.4d4772e8c73e6b07efc6ad57672d4673.js',
'https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js'
);

if (workbox) {
console.log('Workbox loaded');
workbox.precaching.precacheAndRoute(self.__precacheManifest);
// additional service worker code
} else {
console.log('Error loading workbox');
}

Using GenerateSW will not take our existing service worker file into consideration, and it'll always output what we could consider the "default".

Workbox and plugins

Since Vue under the hood uses Workbox, we can leverage the plugin based system that comes with Workbox. In a previous article we have discussed how to use the Cloudinary plugin to adaptively load images based on the network connection of the user. We can use the same plugin in our current code as well.

Develop and benefit

The beautiful thing about using Vue with the PWA plugin is that we can keep on developing our application and at build time all the assets that we use are going to be added to the precache manifest, and therefore they'll automatically form part of the service worker.

Installation

Astute developers may have noticed already that upon executing a build, we not only get a service worker and a precache manifest file generated but we also get manifest.json added to the dist folder. This is the file that contains "metadata" about the PWA - the name, icons, a start URL, amongst other things. By having this file in place, our PWA is installable pretty much straight away. This is another additional benefit of letting Vue generate the PWA for us.

Conclusion

Progressive Web Applications have great benefits that include enhanced performance as well as giving users an app-like functionality. Using the appropriate plugin, Vue developers can also leverage the benefits of Workbox - an open-source set of JavaScript libraries created by Google to aid developers in creating amazing PWAs.