DEV Community

mweissen
mweissen

Posted on

3 2

Sapper with "cache-first"

The serviceworker of Sapper works with network first, falling back to cache if the user is offline. How to change the serviceworker to implement cache-first instead of network-first?

service-worker.js:

import { timestamp, files, shell, routes } from '@sapper/service-worker';

const ASSETS = `cache${timestamp}`;

// `shell` is an array of all the files generated by the bundler,
// `files` is an array of everything in the `static` directory
const to_cache = shell.concat(files);
const cached = new Set(to_cache);


self.addEventListener('install', event => {
    event.waitUntil(
        caches
            .open(ASSETS)
            .then(cache => cache.addAll(to_cache))
            .then(() => {
                self.skipWaiting();
            })
            .then(console.log("install ASSETS", ASSETS)) 
    );
});

self.addEventListener('activate', event => {
    event.waitUntil(
        caches.keys().then(async keys => {
            // delete old caches
            for (const key of keys) {
                if (key !== ASSETS) await caches.delete(key);
                }
            self.clients.claim();
        })
    );
});

self.addEventListener('fetch', event => {

    if (event.request.method !== 'GET' || event.request.headers.has('range')) return;

    const url = new URL(event.request.url);

    // don't try to handle e.g. data: URIs
    if (!url.protocol.startsWith('http')) return;

    // ignore dev server requests
    if (url.hostname === self.location.hostname && url.port !== self.location.port) return;

    // always serve static files and bundler-generated assets from cache
    if (url.host === self.location.host && cached.has(url.pathname)) {
        event.respondWith(caches.match(event.request));
        return;
    }

    // for pages, you might want to serve a shell `service-worker-index.html` file,
    // which Sapper has generated for you. It's not right for every
    // app, but if it's right for yours then uncomment this section
    /*
    if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
        event.respondWith(caches.match('/service-worker-index.html'));
        return;
    }
    */

    if (event.request.cache === 'only-if-cached') return;

    // for everything else, try the network first, falling back to
    // cache if the user is offline. (If the pages never change, you
    // might prefer a cache-first approach to a network-first one.)

    event.respondWith(
        caches
            .open(`offline${timestamp}`)
            .then(async cache => {
                try {
                    const response = await fetch(event.request);
                    cache.put(event.request, response.clone());
                    return response;
                } catch(err) {
                    const response = await cache.match(event.request);
                    if (response) return response;

                    throw err;
                }
            })
    );
});
đź‘‹ While you are here

Reinvent your career. Join DEV.

It takes one minute and is worth it for your career.

Get started

Top comments (1)

Collapse
 
anirudhkonduru profile image
Anirudh Konduru •

This seems to be identical to the service-worker.js that comes with the sapper starter project, without the change required to make it cache-first.
An short fix for anyone looking for the solution: replace the try block in the very last few lines with this:

let response = await cache.match(event.request);
if (response) return response;
response = await fetch(event.request);
cache.put(event.request, response.clone());
return response;

Heroku

This site is powered by Heroku

Heroku was created by developers, for developers. Get started today and find out why Heroku has been the platform of choice for brands like DEV for over a decade.

Sign Up

đź‘‹ Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay