homeresume
 
   

Caching with service worker and Workbox

January 28, 20214 min read

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, 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'));
});
}
Installation

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

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

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

Activation

activate event is dispatched once the old service worker is gone and new one is able to control clients. skipWaiting method during the install event ensures that any new version will become activated immediately, it should be used with clientsClaim to ensure all active clients are controlled immediately by the new service worker. The outdated cache can be deleted during the mentioned event.

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

Workbox

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

importScripts(`https://storage.googleapis.com/workbox-cdn/releases/${WORKBOX_VERSION}/workbox-sw.js`);
const {
cacheableResponse: { CacheableResponsePlugin },
expiration: { ExpirationPlugin },
routing: { registerRoute },
strategies: { CacheFirst, StaleWhileRevalidate },
} = workbox;

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, it allows serving cached files without network access. Runtime caching refers to gradually adding responses to a cache, it allows serving cached files 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, the response will be used to update the cache. If the cached response is not available, network response will be passed back to the app. This strategy can be used when showing the resource immediately is key, even if it's an older value.

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

With cache-first strategy, the cached response is retrieved if available, and the network won't be used at all. If the cached response is not available, the response is retrieved from the network. In that case, network response will update the cache. This strategy can be used 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,
}),
],
}),
);
Network-first

With a network-first strategy, the service worker tries to fetch the response from the network, if it is successful, the cache will be updated with the response. If the network response fails, the cached response will be used. This strategy can be used for resources whose newest update is important but still needed offline.

Cache-only

This strategy can be used for precached files (e.g. default offline page).

Network-only

This strategy can be used for non-GET requests (e.g. forms).

Željko Šević

Željko Šević

Software Engineer, Node.js Developer

 

© 2021