DEV Community

Željko Šević
Željko Šević

Posted on • Originally published at sevic.dev on

Caching with service worker and Workbox

This blog post covers service worker basics and different caching strategies with service workers and Workbox.

Service worker

A service worker is a network proxy that can intercept and handle requests and cache or retrieve resources from the cache. It is a script running in the background, separately from the main browser thread.

Lifecycle

Registration

Registration can happen after the page is loaded. Browser support and HTTPS are the main prerequisites.

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js')
      .then(() => console.log('Service worker is registered!'))
      .catch(() => console.error('Service worker registration failed'));
  });
}
Enter fullscreen mode Exit fullscreen mode
Installation

The install event is emitted when a new or modified service worker file exists. Assets can be precached during the mentioned event.

self.addEventListener('install', (event) => {
  // cache assets
});
Enter fullscreen mode Exit fullscreen mode
Waiting

After successful installation, the updated service worker delays activating until the existing service worker no longer controls clients.

Activation

The activate event is dispatched once the old service worker is gone and a new one can control clients.

The skipWaiting method during the install event ensures that any new version will become activated immediately. Use it with clientsClaim to ensure the new service worker controls all active clients directly.

The outdated cache can be deleted during the mentioned event.

self.addEventListener('activate', (event) => {
  // clear outdated cache
});
Enter fullscreen mode Exit fullscreen mode

Workbox

Workbox is a set of libraries that makes building offline progressive web apps easier. It contains libraries for precaching, runtime caching, and caching strategies, to name a few.

importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.5.4/workbox-sw.js');

const {
  cacheableResponse: { CacheableResponsePlugin },
  expiration: { ExpirationPlugin },
  routing: { registerRoute },
  strategies: { CacheFirst, StaleWhileRevalidate },
} = workbox;
Enter fullscreen mode Exit fullscreen mode

Caching

Caching ensures the app loads as efficiently as possible for repeat visitors. Precaching and runtime caching will be covered briefly.

Precaching means saving files to the cache during the service worker installation and allowing it to serve cached files without network access.

Runtime caching refers to gradually adding responses to a cache, and it allows serving cached files by combining cache and network in multiple ways.

Common runtime caching strategies

Stale-while-revalidate

With the stale-while-revalidate strategy, the cached response is retrieved if available. The service worker will also send a network request to get the latest version, and the response will update the cache.

If the cached response is unavailable, the network response will be passed back to the app.

Use this strategy when showing immediately the resource is vital, even if it's an older value.

registerRoute(
  ({ request }) => request.mode === 'navigate',
  new StaleWhileRevalidate({
    cacheName: 'pages',
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
    ],
  }),
);
Enter fullscreen mode Exit fullscreen mode
Cache-first

With the cache-first strategy, the cached response is retrieved if available, and the network won't be used.

If the cached response is not available, the response is retrieved from the network. In that case, the network response will update the cache.

Use this strategy for assets that are unlikely to change (e.g., font files, images).

registerRoute(
  ({ request }) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images',
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
      new ExpirationPlugin({
        maxEntries,
        maxAgeSeconds,
      }),
    ],
  }),
);
Enter fullscreen mode Exit fullscreen mode
Network-first

With a network-first strategy, the service worker tries to fetch the response from the network, and if it is successful, the cache will be updated with the response.

If the network response fails, the cached response will be used.

Use this strategy for resources whose newest update is essential but still needed offline.

Cache-only

Use this strategy for precached files (e.g., default offline page).

Network-only

Use this strategy for non-GET requests (e.g., forms).

Demo

The demo with the mentioned examples for the Progressive Web App is available here.

Boilerplate

Here is the link to the boilerplate I use for the development. It contains the examples mentioned above with more details.

Top comments (0)