Skip to content

Instantly share code, notes, and snippets.

@baptistemanson
Last active January 5, 2023 16:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baptistemanson/d38c260b68acd64cbbb2cb764b00721d to your computer and use it in GitHub Desktop.
Save baptistemanson/d38c260b68acd64cbbb2cb764b00721d to your computer and use it in GitHub Desktop.
example hack for service worker
useEffect(() => {
if (!navigator.serviceWorker)
throw new Error("We only support browsers with service workers enabled");
// The trickery below appears to be necessary to register a compiled ServiceWorker with nextjs
// Webpack only compiles workers imported via the pattern `new Worker(new URL("script_to_be_compiled"))`
// So we need to use that exact expression and have it register a service worker instead
const RealWorker = window.Worker;
(
window as any
).Worker = class FakeWorkerRegisteringServiceWorkerToTrickNextjs {
constructor(url: URL) {
// We need to change the scope to / since the script compiled by nextjs will be placed in the _next/static/chunks directory
// By default the service worker takes the scope of its source files and only handles requests from pages under that scope
// To change the scope we must allow it by attaching the Service-Worker-Allowed header (see next.config.js)
navigator.serviceWorker.register(url, { scope: "/" }).then(
async (_registration) => {
await navigator.serviceWorker.ready;
debug("sync-main")("service worker is ready");
setIsSWReady(true);
},
(err) => console.error(err),
);
}
};
new Worker(new URL("../service-worker/index.ts", import.meta.url));
window.Worker = RealWorker;
// The ServiceWorker that was just registered still needs to "claim" this page
// and the `navigator.serviceWorker.controller` will not be available until this happes
// Waiting on the navigator.serviceWorker.register(...) promise or navigator.serviceWorker.ready
// is not enough, since a service worker may be activated without claiming pages at all
navigator.serviceWorker.addEventListener("controllerchange", (e) => {
debug("sync-main")("change of controller");
setSWId(nanoid());
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment