Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider extracting functionality into service worker and window modules? #16

Closed
jcbhmr opened this issue Jul 17, 2023 · 4 comments
Closed

Comments

@jcbhmr
Copy link

jcbhmr commented Jul 17, 2023

This would make it easier to compose with an existing application and service worker.

example idea that I had

// main.js
import doThing from "your-package/window.js";

// THIS WILL EXECUTE TWICE since the page is reloaded
console.log("before", crossOriginIsolated);
//=> false (first time)
//=> true (second time)

// It will hang here and reload the page (think process.exit()-like)
await doThing(navigator.serviceWorker?.register("sw.js", { type: "module" }));

// THIS WILL EXECUTE ONCE the second time
console.log("after", crossOriginIsolated);
//=> true
// sw.js
// This auto-registers the 'fetch' event listener, but don't worry! You can
// still add your own listeners! It's just a fallback for any you don't handle.
import "your-package/sw.js";

// REQUIRED(?)
globalThis.addEventListener("install", () => skipWaiting());
globalThis.addEventListener("activate", (e) => e.waitUntil(clients.claim()));

globalThis.addEventListener("fetch", (e) => {
  // We also add a 'fetch()' wrapper polyfill to add the COOP and COEP headers
  // to any fetch requests you make that would have been handled by our 'fetch'
  // event handler. This way, 👇 this still works! If we didn't override the
  // 'fetch()' function, this wouldn't get the right headers.
  e.respondWith(fetch(e.request));
});

cc @gzuidhof

@gzuidhof
Copy link
Owner

I'd propose to avoid top level await wherever you can, but that doesn't mean we couldn't somehow expose a Promise that can be awaited if someone does wish to use such a top level await.

I imagine that to support this we would either

  • Put something in global scope.. Kind of ugly (e.g. putting a variable called coi on window).
  • Provide an ESM module build that exports some goodies.

As for splitting up the main.js and sw.js, at that point I would wonder why one would use coi-serviceworker at all? It's quite a bit more involved - perhaps this makes sense as a blogpost that people can copy paste recipes from, instead of a library.

Other than providing a Promise, why would one not be able to put their own if/else on crossOriginIsolated, and depending on that show content or not? Relevant issue: #14 - Could you help me understand why a top level await that blocks forever is better than

if (!window.crossOriginIsolated) {
  throw new Error("Oh no!")
}

@jcbhmr
Copy link
Author

jcbhmr commented Jul 21, 2023

I guess it's more of a question of what you consider in-scope. Is this supposed to be:

  1. Just a <script> tag and that's it
  2. A collection of helpful COI utils for simple apps (with an AiO <script> tag)

For the second option, here's some ideas of other utils that could be included:

  • A Vite plugin to auto-insert the AiO <script> tag
  • A quick CLI or something to auto-inject the <script> tag into a single file or folder -- this could be useful for projects that generate HTML output like TypeDoc
  • A service worker plugin that you can call or something (or that auto-injects; idk) to compose these COI headers with the rest of your cache logic stuff
  • A whiteout frozen "loading" until the service worker gets setup
  • An ESM js script that you can import and expect it to "lock until loaded"

All of those things 👆 could also just be examples since the code to do them is so minimal. i.e.

  • A quick demo of the Vite https://vitejs.dev/config/server-options.html#server-headers option
  • A quick copy-paste curl + sed command to inject the AiO script
  • A quick <details> or something on how to take the simple logic and apply it in your own SW
  • An example/copy-paste sample or something to demo "don't show content until COI"
  • A demo of location.reload(); await new Promise(() => {})

you're right, it's very easy to copy-paste the relevant bits into your service worker.

If you want to go with that I'd suggest putting at least an excerpt of whatever blog post in the readme. like > excerpt or something idk

@jcbhmr jcbhmr closed this as not planned Won't fix, can't repro, duplicate, stale Jul 21, 2023
@jcbhmr

This comment was marked as off-topic.

@gzuidhof
Copy link
Owner

Aha ok, thank you for helping me understand a bit better, maybe something like the following could do the job for displaying something without needing any additional errors or never-resolving-awaits:

if (!window.crossOriginIsolated) {
 const e = document.createElement("div");
 e.innerText = "Please wait while the page refreshes..."
 const s = e.style;
 s.position = "absolute"
 s.zIndex = "10000"
 s.width = "100%"
 s.height = "100%"
 s.backgroundColor = "#FFF"
 
 document.body.appendChild(e);
}

I like the idea of having a set of examples / recipes a lot - it is great if people can copy paste snippets of code into their projects without them needing to add a dependency. For those who want a more involved integration, we can of course also link to the tinycoi library where it makes sense

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants