Vue PWA: Use ServiceWorker to cache remote media assets from array of URLs

Viewed 1153

I am building a PWA where I would like to optionally download and cache ALL media assets used throughout the application, if the user wants to. The default PWA behaviour only caches the assets when they are requested navigating around the app. I need to offer the functionality to press the button, download the assets, go offline and use the entire app and have all the assets cached witout necessarily visiting the various routes and views while online.

For context, when the app loads, Vuex grabs the JSON content from my API, puts it in state, and saves to IndexedDB.

If the user clicks the 'download everything' button, I want to parse the JSON in $store.state, collect the URLs (images, PDFs and MP4s) into an array and pass that array to the ServiceWorker to deliberately cache all the assets at those URLs for offline use (up to the allowed origin storage limit).

I'm using Vue CLI and the Vue PWA plugin, so I have the registerServiceWorker.js file and precache manifest is generated for production.

I find the info on the internet about this slightly confusing I was thinking to use the approach outlined by https://developers.google.com/web/ilt/pwa/lab-caching-files-with-service-worker but I'm not sure about some of the specifics, and also unsure about how to tackle this in a way that fits in nicely with Vue CLI workflow?

If possible, can you include the following questions in your answer:

  1. Do I use GenerateSW or InjectManifest?

  2. Do I need to write my own Service Worker, or can I hook into the lifecycle methods (registered(), cached(), updated()) in registerServiceWorker.js?

Thank you in advance for your help.

1 Answers

I found a way to cache remote files on Vue 3, Vue CLI PWA app.

  1. Set up the vue.conig.js on the root directory as shown below

# vue.config.js
module.exports = {
  // ...other vue-cli plugin options...
  pwa: {
    name: "my-pwa-app",
    themeColor: "#624040",
    msTileColor: "#000000",
    // configure the workbox plugin
    workboxPluginMode: "InjectManifest",
    workboxOptions: {
      // swSrc is required in InjectManifest mode.
      swSrc: "service-worker.js", //path to your own service-worker file
      // ...other Workbox options...
    },
  },
};

  1. Create the service-worker.js with starter code below, add other functionalities you need for caching

# service-worker.js
// workbox functions from the workbox CDN (version 4.3.1) 
// Vue 3 PWA automatically adds the CDN
const { precacheAndRoute } = workbox.precaching;
const { registerRoute } = workbox.routing;
const { CacheFirst, StaleWhileRevalidate } = workbox.strategies;
const { Plugin: ExpirationPlugin } = workbox.expiration;
const { Plugin: CacheableResponsePlugin } = workbox.cacheableResponse;

workbox.core.setCacheNameDetails({ prefix: "appname" });

self.addEventListener("message", (event) => {
  if (event.data && event.data.type === "SKIP_WAITING") {
    self.skipWaiting();
  }
});

/**
 * The workboxSW.precacheAndRoute() method efficiently caches and responds to
 * requests for URLs in the manifest.
 */
self.__precacheManifest = [].concat(self.__precacheManifest || []);
precacheAndRoute(self.__precacheManifest, {});

// cache image and render from the cache if it exists or go t the network
registerRoute(
  ({ request }) => request.destination === "image",
  new CacheFirst({
    cacheName: "images",
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
      new ExpirationPlugin({
        maxEntries: 60,
        maxAgeSeconds: 2 * 24 * 60 * 60, // cache the images for only 2 Days
      }),
    ],
  })
);

// cache API response and serve from cache if exists or go to the network 
registerRoute(
  ({ url }) => url.pathname.startsWith("https://dog.ceo/api/"),
  new StaleWhileRevalidate()
);

VueJs takes the service-worker.js and adds its import for the precaching of the files from the /dist folder

  • Documentation for Workbox could be found here
  • Notes on workbox 4.3.1 I found useful here
Related