Serviceworker: Make Service Worker control only specific pages

Created on 8 Oct 2016  Â·  10Comments  Â·  Source: w3c/ServiceWorker

My use case is to have service workers intercept fetch requests only from a few specific pages. Right now, the only way to control which fetch requests the service worker controls is via the scope parameter via registration, but that is not granular enough.

It would be great if I could mention which pages the SW should control on registration.

Most helpful comment

@inian you can't call respondWith asynchronously. It'd need to be more like:

const pagesToControl = ["/page1.html", "/page2.html"];

self.addEventListener("fetch", function(e) {
  e.respondWith(function() {
    if (!e.clientId) return fetch(e.request);
    return clients.get(e.clientId).then(client => {
      const clientURL = new URL(client.url);

      if (!pagesToControl.includes(clientURL.pathname)) {
        return fetch(e.request);
      }

      // respond to fetch request
    });
  }());
});

All 10 comments

@inian you can just don't handle requests if you don't need them.

Is there an easy way from a fetch event to identify the page making the request? For example, I want to intercept sub-resources from /page1.html and /page3.html but not from /page2.html. What would be the easiest way to go about doing this?

you could try placing /page1.html and /page3.html in a directory (eg. /staticHtml/) and set the SW scope to that folder.

https://mdn.mozillademos.org/files/12630/important-notes.png
https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers

I was having a tough time understanding scopes. ^ the diagram sort of clears things up.

@inian fetchEvent.clientId gives you the id of the client. You can do clients.get(clientId).then(client => …) to get additional information about the client.

Ah clients.get is what I was looking for. Thanks Jake!

@inian do you mind uploading some code on how this helped your case?

@lmj0011 This is what I came up with

self.addEventListener("fetch", function(e) {
    if (e.clientId) {
        clients
        .get(e.clientId)
        .then((client) => {
            if(client.url == "page1.html" || client.url == "page2.html") {
                // respond to fetch request
            } else {
                // pass through
                e.respondWith(fetch(e.requestURL));
            }
        });
    } else {
        // pass through for navigation request
        e.respondWith(fetch(e.requestURL));
    }
});

Okay, that's what I'm doing. I was looking to see if changed the registration scope

Yup, declaring them at registration time was what i was looking for but this is good enough for me now..

@inian you can't call respondWith asynchronously. It'd need to be more like:

const pagesToControl = ["/page1.html", "/page2.html"];

self.addEventListener("fetch", function(e) {
  e.respondWith(function() {
    if (!e.clientId) return fetch(e.request);
    return clients.get(e.clientId).then(client => {
      const clientURL = new URL(client.url);

      if (!pagesToControl.includes(clientURL.pathname)) {
        return fetch(e.request);
      }

      // respond to fetch request
    });
  }());
});
Was this page helpful?
0 / 5 - 0 ratings

Related issues

lewispham picture lewispham  Â·  12Comments

mfalken picture mfalken  Â·  10Comments

jakearchibald picture jakearchibald  Â·  11Comments

annevk picture annevk  Â·  9Comments

h2non picture h2non  Â·  11Comments