Skip to main content

Creating Progressive Web Apps with Vue

6 min read

Older Article

This article was published 7 years ago. Some information may be outdated or no longer applicable.

Progressive Web Applications are websites that behave like native apps. They support notifications and they keep working when the network drops.

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

Here we’ll walk through creating a Progressive Web Application (PWA) using Vue.js.

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

This article doesn’t cover the basics of Progressive Web Applications. Readers should already be familiar with PWA fundamentals. If you’d like to learn more, check out my book on the topic.

Create the Vue app

First, install the Vue CLI by running npm i -g @vue/cli, then create an app with vue create vue-pwa.

The CLI asks a few questions. Choose “Manually select features” instead of a preset.

Here’s what I selected (you can pick different options, but the PWA feature must be ticked):

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

Open the project source and you’ll notice there’s no service worker file, though there is a registerServiceWorker.js file that registers a service worker based on this 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

Vue only generates a service worker for production builds. Let’s trigger one by running npm run build. (You can also use npm run serve --build.)

Once the command finishes, open the resulting dist folder. A new file called service-worker.js sits there.

This is an automatically generated service worker. Under the hood, it uses Workbox (version 3.6.3 at the time of writing, though the latest was 4.3.1. You can manually update this, bearing in mind each rebuild resets it).

If you’re new to Workbox, I’d suggest reading about it here.

Precaching

Precaching means downloading files (usually static assets needed for an app to run) ahead of time, before the Service Worker installs. That makes these files immediately available offline.

Open dist/precache-manifest.[hash].js and you’ll see all the files that make up the Vue app, each with a revision and a URL. Workbox uses this information to place files in the cache. By checking the revision (just an md5 sum of the file content), it can tell whether a file has changed and needs updating in the cache.

Customising the service worker

Everything works out of the box. But sometimes you need to customise the service worker to fit your needs. Let’s look at how.

Customisation happens via vue.config.js using Workbox configuration options.

What can we configure? There are two types of configuration: one specific to Workbox, the other specific to the Vue PWA plugin itself. Let’s start with the latter.

  • iconPaths: specifies the locations for Android, Apple and Microsoft mobile icons since each device has different dimension requirements (the options are favicon16, favicon32, appleTouchIcon, maskIcon and msTileImage). They all have default values.

  • themeColor: sets a hexadecimal colour value for the application on mobile interfaces.

For the Workbox configuration options:

  • workboxPluginMode: set this to either GenerateSW or InjectManifest (more on this below).
  • workboxOptions: pass in extra options for Workbox.

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

GenerateSW vs InjectManifest

GenerateSW (the default) creates a fresh service worker file whenever the app gets rebuilt.

InjectManifest lets us start with an existing service worker. The build script creates a copy of it with a “precache manifest” injected into it.

Depending on which method you choose, different options are available.

GenerateSW

With GenerateSW, you can specify options like swDest (defaults to service-worker.js) to set the path and filename of the service worker file the build process creates.

InjectManifest

With InjectManifest, you can specify swDest (same as above) plus swSrc, which should point to an existing service worker file.

A sample service worker file

Here’s what an example service worker file looks like when used with InjectManifest:

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

In the above, self.__precacheManifest refers to the file that Vue generates automatically, containing the list of assets we mentioned.

After the build, the resulting service worker file picks up one extra line that imports the precacheManifest 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 ignores any existing service worker file and always outputs what we’d consider the “default.”

Workbox and plugins

Since Vue uses Workbox under the hood, we can tap into the plugin-based system that comes with it. In a previous article we covered how to use the Cloudinary plugin to adaptively load images based on the user’s network connection. The same plugin works in our current code too.

Develop and benefit

The beautiful thing about using Vue with the PWA plugin: we can keep developing our application and at build time all assets get added to the precache manifest automatically. They become part of the service worker without any extra effort.

Installation

Sharp-eyed developers may have noticed that running a build doesn’t just generate a service worker and a precache manifest. It also drops a manifest.json into the dist folder. This file holds “metadata” about the PWA: the name, icons, a start URL, among other things. With this file in place, our PWA is installable more or less straight away. That’s another perk of letting Vue generate the PWA for us.

Conclusion

Progressive Web Applications bring real performance benefits and give users app-like functionality. Using the appropriate plugin, Vue developers can tap into Workbox, an open-source set of JavaScript libraries created by Google that makes building solid PWAs considerably easier.