w3c / w3c/ServiceWorker

Allow better composability of fetch handlers

Open
#1,482 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Bikeshed
Stars
3.6k
Forks
324
Avg merge
14d 22h
Merged PRs (30d)
1

Description

I'm working on implementing default service worker support for Parcel. We'd like to inject some code into service workers at build time to handle Parcel generated assets, but still allow users to write custom code to handle other types of requests themselves (e.g. site content, APIs, etc.).

Currently, if a fetch handler does not call event.respondWith() synchronously within the handler, the event continues propagating to the next handler and so on. This is quite useful for allowing fallback, either to another handler or to the browser. However, if the logic to determine whether to respond to a request or not is asynchronous (e.g. loading something from cache or IDB), then it's impossible. By the time you've decided to respond, it's too late - the request has already been handled by something else.

I would like a way to make a decision about whether to respond to a fetch event asynchronously. I can think of two options, but I'm open to others:

  1. event.continuePropagation() - the opposite of stopPropagation(). You call event.respondWith() as normal, but once you've decided not to actually respond, you continue propagation to the next handler.
self.addEventListener('fetch', event => {
  event.respondWith(async () => {
    if (await shouldRespond(event.request)) {
      return getResponse(event.request);
    }

    event.continuePropagation();
  }());
});
  1. Allow event.respondWith() to be called from within an event.waitUntil() promise. This one might not work because I believe waitUntil causes the worker to wait, not the request, but I could be wrong.
self.addEventListener('fetch', event => {
  event.waitUntil(async () => {
    if (await shouldRespond(event.request)) {
      return event.respondWith(getResponse(event.request));
    }
  }());
});

Previous discussions

This has previously been discussed in 2016 in #836, and probably a few other issues as well. The recommendation at the time seemed to be to use a middleware pattern. This works well if the service worker is all written together, but when tooling like Parcel wants to inject logic into a service worker it falls down. We would like to avoid inventing our own service worker middleware framework or requiring users use a specific library to write their service worker.

See also this twitter thread: https://twitter.com/devongovett/status/1185961634029654016, and our RFC for service worker generation in Parcel: https://github.com/parcel-bundler/parcel/issues/3661.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the previous discussion in issue #836 and the linked Parcel service-worker generation RFC. Define and document an agreed way for asynchronously deciding whether a fetch event should respond or continue, with behavior that supports injected handlers alongside user handlers.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.