[w3c/ServiceWorker] Allow better composability of fetch handlers (#1482)

I'm working on implementing default service worker support for [Parcel](https://github.com/parcel-bundler/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.

```javascript
self.addEventListener('fetch', event => {
  event.respondWith(async () => {
    if (await shouldRespond(event.request)) {
      return getResponse(event.request);
    }

    event.continuePropagation();
  }());
});
```

2. 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.

```javascript
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.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/ServiceWorker/issues/1482

Received on Sunday, 20 October 2019 23:09:02 UTC