From 3967d26f9dca2dde885749716d95356e89c3090d Mon Sep 17 00:00:00 2001 From: R Midhun Suresh Date: Fri, 16 Aug 2024 15:30:44 +0530 Subject: [PATCH] Make service worker work in dev --- scripts/build-plugins/sw-dev.js | 67 ++++++++++++ src/platform/web/index.html | 4 +- src/platform/web/public/icon.png | Bin 0 -> 15862 bytes src/platform/web/sw.js | 180 ++++++++++++++++++++----------- 4 files changed, 185 insertions(+), 66 deletions(-) create mode 100644 scripts/build-plugins/sw-dev.js create mode 100644 src/platform/web/public/icon.png diff --git a/scripts/build-plugins/sw-dev.js b/scripts/build-plugins/sw-dev.js new file mode 100644 index 00000000..876ba43e --- /dev/null +++ b/scripts/build-plugins/sw-dev.js @@ -0,0 +1,67 @@ +/* +Copyright 2024 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import fs from "fs/promises"; +import path from "path"; + +/** + * This rollup plugin makes it possible to use the serviceworker with the dev server. + * The service worker is located in `/src/platform/web/sw.js` and it contains some + * fields that need to be replaced with sensible values. + * + * We have a plugin that does this during build (see `./service-worker.js`). + * This plugin does more or less the same but for dev. + */ + +export function transformServiceWorkerInDevServer() { + // See https://vitejs.dev/config/shared-options.html#define + // Comes from vite.config.js + let define; + + return { + name: "hydrogen:transformServiceWorkerInDevServer", + apply: "serve", + enforce: "pre", + + configResolved(resolvedConfig) { + // store the resolved config + define = resolvedConfig.define; + }, + + async load(id) { + if (!id.includes("sw.js")) return null; + let code = await readServiceWorkerCode(); + for (const [key, value] of Object.entries(define)) { + code = code.replaceAll(key, value); + } + return code; + }, + }; +} + +/** + * Read service worker code from `src/platform/web/sw.js` + * @returns code as string + */ +async function readServiceWorkerCode() { + const resolvedLocation = path.resolve( + __dirname, + "../../", + "./src/platform/web/sw.js" + ); + const data = await fs.readFile(resolvedLocation, { encoding: "utf-8" }); + return data; +} diff --git a/src/platform/web/index.html b/src/platform/web/index.html index 16418699..37bfec1c 100644 --- a/src/platform/web/index.html +++ b/src/platform/web/index.html @@ -19,9 +19,7 @@ import {Platform} from "./Platform"; import configURL from "./assets/config.json?url"; import assetPaths from "./sdk/paths/vite"; - if (import.meta.env.PROD) { - assetPaths.serviceWorker = "sw.js"; - } + assetPaths.serviceWorker = "sw.js"; const platform = new Platform({ container: document.body, assetPaths, diff --git a/src/platform/web/public/icon.png b/src/platform/web/public/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b6c70c00a4957f34bda8d23ef1dd258f074f8764 GIT binary patch literal 15862 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 literal 0 HcmV?d00001 diff --git a/src/platform/web/sw.js b/src/platform/web/sw.js index 088bc059..2c0aca5f 100644 --- a/src/platform/web/sw.js +++ b/src/platform/web/sw.js @@ -15,8 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import NOTIFICATION_BADGE_ICON from "./assets/icon.png?url"; -// replaced by the service worker build plugin +const NOTIFICATION_BADGE_ICON = "icon.png"; + +// These are replaced by rollup plugins const UNHASHED_PRECACHED_ASSETS = DEFINE_UNHASHED_PRECACHED_ASSETS; const HASHED_PRECACHED_ASSETS = DEFINE_HASHED_PRECACHED_ASSETS; const HASHED_CACHED_ON_REQUEST_ASSETS = DEFINE_HASHED_CACHED_ON_REQUEST_ASSETS; @@ -25,20 +26,24 @@ const unhashedCacheName = `hydrogen-assets-${DEFINE_GLOBAL_HASH}`; const hashedCacheName = `hydrogen-assets`; const mediaThumbnailCacheName = `hydrogen-media-thumbnails-v2`; -self.addEventListener('install', function(e) { - e.waitUntil((async () => { - const unhashedCache = await caches.open(unhashedCacheName); - await unhashedCache.addAll(UNHASHED_PRECACHED_ASSETS); - const hashedCache = await caches.open(hashedCacheName); - await Promise.all(HASHED_PRECACHED_ASSETS.map(async asset => { - if (!await hashedCache.match(asset)) { - await hashedCache.add(asset); - } - })); - })()); +self.addEventListener("install", function (e) { + e.waitUntil( + (async () => { + const unhashedCache = await caches.open(unhashedCacheName); + await unhashedCache.addAll(UNHASHED_PRECACHED_ASSETS); + const hashedCache = await caches.open(hashedCacheName); + await Promise.all( + HASHED_PRECACHED_ASSETS.map(async (asset) => { + if (!(await hashedCache.match(asset))) { + await hashedCache.add(asset); + } + }) + ); + })() + ); }); -self.addEventListener('activate', (event) => { +self.addEventListener("activate", (event) => { // on a first page load/sw install, // start using the service worker on all pages straight away self.clients.claim(); @@ -49,26 +54,29 @@ async function purgeOldCaches() { // remove any caches we don't know about const keyList = await caches.keys(); for (const key of keyList) { - if (key !== unhashedCacheName && key !== hashedCacheName && key !== mediaThumbnailCacheName) { + if ( + key !== unhashedCacheName && + key !== hashedCacheName && + key !== mediaThumbnailCacheName + ) { await caches.delete(key); } } // remove the cache for any old hashed resource const hashedCache = await caches.open(hashedCacheName); const keys = await hashedCache.keys(); - const hashedAssetURLs = - HASHED_PRECACHED_ASSETS - .concat(HASHED_CACHED_ON_REQUEST_ASSETS) - .map(a => new URL(a, self.registration.scope).href); + const hashedAssetURLs = HASHED_PRECACHED_ASSETS.concat( + HASHED_CACHED_ON_REQUEST_ASSETS + ).map((a) => new URL(a, self.registration.scope).href); for (const request of keys) { - if (!hashedAssetURLs.some(url => url === request.url)) { + if (!hashedAssetURLs.some((url) => url === request.url)) { hashedCache.delete(request); } } } -self.addEventListener('fetch', (event) => { +self.addEventListener("fetch", (event) => { /* service worker shouldn't handle xhr uploads because otherwise the progress events won't fire. @@ -95,12 +103,18 @@ let pendingFetchAbortController = new AbortController(); async function handleRequest(request) { try { - if (request.url.includes("config.json") || /theme-.+\.json/.test(request.url)) { + if ( + request.url.includes("config.json") || + /theme-.+\.json/.test(request.url) + ) { return handleStaleWhileRevalidateRequest(request); } const url = new URL(request.url); // rewrite / to /index.html so it hits the cache - if (url.origin === baseURL.origin && url.pathname === baseURL.pathname) { + if ( + url.origin === baseURL.origin && + url.pathname === baseURL.pathname + ) { request = new Request(new URL("index.html", baseURL.href)); } let response = await readCache(request); @@ -108,9 +122,15 @@ async function handleRequest(request) { // use cors so the resource in the cache isn't opaque and uses up to 7mb // https://developers.google.com/web/tools/chrome-devtools/progressive-web-apps?utm_source=devtools#opaque-responses if (isCacheableThumbnail(url)) { - response = await fetch(request, {signal: pendingFetchAbortController.signal, mode: "cors", credentials: "omit"}); + response = await fetch(request, { + signal: pendingFetchAbortController.signal, + mode: "cors", + credentials: "omit", + }); } else { - response = await fetch(request, {signal: pendingFetchAbortController.signal}); + response = await fetch(request, { + signal: pendingFetchAbortController.signal, + }); } await updateCache(request, response); } @@ -184,7 +204,7 @@ async function readCache(request) { if (response) { return response; } - + const url = new URL(request.url); if (isCacheableThumbnail(url)) { const mediaThumbnailCache = await caches.open(mediaThumbnailCacheName); @@ -198,9 +218,10 @@ async function readCache(request) { return response; } -self.addEventListener('message', (event) => { - const reply = payload => event.source.postMessage({replyTo: event.data.id, payload}); - const {replyTo} = event.data; +self.addEventListener("message", (event) => { + const reply = (payload) => + event.source.postMessage({ replyTo: event.data.id, payload }); + const { replyTo } = event.data; if (replyTo) { const resolve = pendingReplies.get(replyTo); if (resolve) { @@ -210,7 +231,10 @@ self.addEventListener('message', (event) => { } else { switch (event.data?.type) { case "version": - reply({version: DEFINE_VERSION, buildHash: DEFINE_GLOBAL_HASH}); + reply({ + version: DEFINE_VERSION, + buildHash: DEFINE_GLOBAL_HASH, + }); break; case "skipWaiting": self.skipWaiting(); @@ -220,8 +244,10 @@ self.addEventListener('message', (event) => { break; case "closeSession": event.waitUntil( - closeSession(event.data.payload.sessionId, event.source.id) - .finally(() => reply()) + closeSession( + event.data.payload.sessionId, + event.source.id + ).finally(() => reply()) ); break; } @@ -235,29 +261,40 @@ async function openClientFromNotif(event) { console.log("clicked notif with tag", event.notification.tag); return; } - const {sessionId, roomId} = event.notification.data; + const { sessionId, roomId } = event.notification.data; const sessionHash = `#/session/${sessionId}`; const roomHash = `${sessionHash}/room/${roomId}`; - const clientWithSession = await findClient(async client => { - return await sendAndWaitForReply(client, "hasSessionOpen", {sessionId}); + const clientWithSession = await findClient(async (client) => { + return await sendAndWaitForReply(client, "hasSessionOpen", { + sessionId, + }); }); if (clientWithSession) { - console.log("notificationclick: client has session open, showing room there"); + console.log( + "notificationclick: client has session open, showing room there" + ); // use a message rather than clientWithSession.navigate here as this refreshes the page on chrome - clientWithSession.postMessage({type: "openRoom", payload: {roomId}}); - if ('focus' in clientWithSession) { + clientWithSession.postMessage({ + type: "openRoom", + payload: { roomId }, + }); + if ("focus" in clientWithSession) { try { await clientWithSession.focus(); - } catch (err) { console.error(err); } // I've had this throw on me on Android + } catch (err) { + console.error(err); + } // I've had this throw on me on Android } } else if (self.clients.openWindow) { - console.log("notificationclick: no client found with session open, opening new window"); + console.log( + "notificationclick: no client found with session open, opening new window" + ); const roomURL = new URL(`./${roomHash}`, baseURL).href; await self.clients.openWindow(roomURL); } } -self.addEventListener('notificationclick', event => { +self.addEventListener("notificationclick", (event) => { event.notification.close(); event.waitUntil(openClientFromNotif(event)); }); @@ -268,19 +305,30 @@ async function handlePushNotification(n) { let sender = n.sender_display_name || n.sender; if (sender && n.event_id) { const roomId = n.room_id; - const hasFocusedClientOnRoom = !!await findClient(async client => { + const hasFocusedClientOnRoom = !!(await findClient(async (client) => { if (client.visibilityState === "visible" && client.focused) { - return await sendAndWaitForReply(client, "hasRoomOpen", {sessionId, roomId}); + return await sendAndWaitForReply(client, "hasRoomOpen", { + sessionId, + roomId, + }); } - }); + })); if (hasFocusedClientOnRoom) { console.log("client is focused, room is open, don't show notif"); return; } - const newMessageNotifs = Array.from(await self.registration.getNotifications({tag: NOTIF_TAG_NEW_MESSAGE})); - const notifsForRoom = newMessageNotifs.filter(n => n.data.roomId === roomId); - const hasMultiNotification = notifsForRoom.some(n => n.data.multi); - const hasSingleNotifsForRoom = newMessageNotifs.some(n => !n.data.multi); + const newMessageNotifs = Array.from( + await self.registration.getNotifications({ + tag: NOTIF_TAG_NEW_MESSAGE, + }) + ); + const notifsForRoom = newMessageNotifs.filter( + (n) => n.data.roomId === roomId + ); + const hasMultiNotification = notifsForRoom.some((n) => n.data.multi); + const hasSingleNotifsForRoom = newMessageNotifs.some( + (n) => !n.data.multi + ); const roomName = n.room_name || n.room_alias; let multi = false; let label; @@ -304,9 +352,9 @@ async function handlePushNotification(n) { } await self.registration.showNotification(label, { body, - data: {sessionId, roomId, multi}, + data: { sessionId, roomId, multi }, tag: NOTIF_TAG_NEW_MESSAGE, - badge: NOTIFICATION_BADGE_ICON + badge: NOTIFICATION_BADGE_ICON, }); } // we could consider hiding previous notifications here based on the unread count @@ -315,25 +363,31 @@ async function handlePushNotification(n) { // when no client is visible, see https://goo.gl/yqv4Q4 } -self.addEventListener('push', event => { +self.addEventListener("push", (event) => { event.waitUntil(handlePushNotification(event.data.json())); }); async function closeSession(sessionId, requestingClientId) { const clients = await self.clients.matchAll(); - await Promise.all(clients.map(async client => { - if (client.id !== requestingClientId) { - await sendAndWaitForReply(client, "closeSession", {sessionId}); - } - })); + await Promise.all( + clients.map(async (client) => { + if (client.id !== requestingClientId) { + await sendAndWaitForReply(client, "closeSession", { + sessionId, + }); + } + }) + ); } async function haltRequests() { // first ask all clients to block sending any more requests - const clients = await self.clients.matchAll({type: "window"}); - await Promise.all(clients.map(client => { - return sendAndWaitForReply(client, "haltRequests"); - })); + const clients = await self.clients.matchAll({ type: "window" }); + await Promise.all( + clients.map((client) => { + return sendAndWaitForReply(client, "haltRequests"); + }) + ); // and only then abort the current requests pendingFetchAbortController.abort(); } @@ -343,15 +397,15 @@ let messageIdCounter = 0; function sendAndWaitForReply(client, type, payload) { messageIdCounter += 1; const id = messageIdCounter; - const promise = new Promise(resolve => { + const promise = new Promise((resolve) => { pendingReplies.set(id, resolve); }); - client.postMessage({type, id, payload}); + client.postMessage({ type, id, payload }); return promise; } async function findClient(predicate) { - const clientList = await self.clients.matchAll({type: "window"}); + const clientList = await self.clients.matchAll({ type: "window" }); for (const client of clientList) { if (await predicate(client)) { return client;