33 Matching Annotations
  1. Jul 2022
  2. Feb 2022
  3. Dec 2021
    1. // main.js
      const { RemoteReadableStream, RemoteWritableStream } = RemoteWebStreams;
      (async () => {
        const worker = new Worker('./worker.js');
        // create a stream to send the input to the worker
        const { writable, readablePort } = new RemoteWritableStream();
        // create a stream to receive the output from the worker
        const { readable, writablePort } = new RemoteReadableStream();
        // transfer the other ends to the worker
        worker.postMessage({ readablePort, writablePort }, [readablePort, writablePort]);
        const response = await fetch('./some-data.txt');
        await response.body
          // send the downloaded data to the worker
          // and receive the results back
          .pipeThrough({ readable, writable })
          // show the results as they come in
          .pipeTo(new WritableStream({
            write(chunk) {
              const results = document.getElementById('results');
              results.appendChild(document.createTextNode(chunk)); // tadaa!
      // worker.js
      const { fromReadablePort, fromWritablePort } = RemoteWebStreams;
      self.onmessage = async (event) => {
        // create the input and output streams from the transferred ports
        const { readablePort, writablePort } = event.data;
        const readable = fromReadablePort(readablePort);
        const writable = fromWritablePort(writablePort);
        // process data
        await readable
          .pipeThrough(new TransformStream({
            transform(chunk, controller) {
              controller.enqueue(process(chunk)); // do the actual work
          .pipeTo(writable); // send the results back to main thread
    1. What you're trying to do is known as the "Application Shell" architectural pattern.

      The trick is to have your service worker's fetch handler check to see whether an incoming request is a navigation (event.request.mode === 'navigate'), and if so, respond with the cached App Shell HTML (which sounds like /index.html in your case).

      A generic way of doing this would be:

      self.addEventListener('fetch', (event) => {
        if (event.request.mode === 'navigate') {
        } else {
          // Your other response logic goes here.

      This will cause your service worker to behave in a similar fashion to how you're web server is already configured.

    1. Fetch and modify response properties which are immutable by creating a copy first.
       * @param {string} headerNameSrc Header to get the new value from
       * @param {string} headerNameDst Header to set based off of value in src
      const headerNameSrc = "foo" //"Orig-Header"
      const headerNameDst = "Last-Modified"
      async function handleRequest(request) {
         * Response properties are immutable. To change them, construct a new
         * Response and pass modified status or statusText in the ResponseInit
         * object. Response headers can be modified through the headers `set` method.
        const originalResponse = await fetch(request)
        // Change status and statusText, but preserve body and headers
        let response = new Response(originalResponse.body, {
          status: 500,
          statusText: "some message",
          headers: originalResponse.headers,
        // Change response body by adding the foo prop
        const originalBody = await originalResponse.json()
        const body = JSON.stringify({ foo: "bar", ...originalBody })
        response = new Response(body, response)
        // Add a header using set method
        response.headers.set("foo", "bar")
        // Set destination header to the value of the source header
        const src = response.headers.get(headerNameSrc)
        if (src != null) {
          response.headers.set(headerNameDst, src)
            `Response header "${headerNameDst}" was set to "${response.headers.get(
        return response
      addEventListener("fetch", event => {
  4. Nov 2021
  5. Sep 2021
    1. Ensure there's only one version of your site running at once. That last one is pretty important. Without service workers, users can load one tab to your site, then later open another. This can result in two versions of your site running at the same time. Sometimes this is ok, but if you're dealing with storage you can easily end up with two tabs having very different opinions on how their shared storage should be managed. This can result in errors, or worse, data loss.

      I wonder how can we identify issues like this when they occur

  6. Mar 2021
    1. However, if these timeouts are moved into a web worker, they should run to time and not get de-prioritised by the browser.
  7. Aug 2020
  8. May 2020
  9. Apr 2020
  10. Nov 2018
  11. Oct 2018
    1. A completely different Service Workers’ storyThis section was added on Feb, 8th.Apple followed the Service Worker API, but it creates an entirely different story of what it is and what we can do with it in the future. The main differences appear when Apple says:“To keep only the stored information that is useful to the user, WebKit will remove unused service worker registrations after a period of a few weeks. Caches that do not get opened after a few weeks will also be removed. Web Applications must be resilient to any individual cache, cache entry or service worker being removed.”https://webkit.org/blog/8090/workers-at-your-service/That is a huge change! At Chrome, Firefox, Samsung Internet, and other browsers, a Service Worker registration is not going to be unregistered automatically, and we can rely on being there in the future. That’s why an installed PWA will be able to work offline in the future. But with Apple’s idea of a service worker, there is no guarantee that the service worker or the cache will be available in the future. It might be if the user comes back to the web app within “a few weeks.” I know, the web app should work anyway while online, but we can’t guarantee one of the key concepts of PWAs: offline access.