From 36bad6cbd0a2261e7298415b76fad8a682533a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A2=96=E9=80=B8?= <49649786+Zuoqiu-Yingyi@users.noreply.github.com> Date: Thu, 23 Nov 2023 00:28:52 +0800 Subject: [PATCH] :art: Improve service worker register and unregister --- app/src/index.ts | 6 ++- app/src/mobile/index.ts | 6 ++- app/src/util/serviceWorker.ts | 84 +++++++++++++++++++++++++++++++++-- 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/app/src/index.ts b/app/src/index.ts index d94256be7c2..9a5e21fbd7c 100644 --- a/app/src/index.ts +++ b/app/src/index.ts @@ -9,7 +9,7 @@ import {addScript, addScriptSync} from "./protyle/util/addScript"; import {genUUID} from "./util/genID"; import {fetchGet, fetchPost} from "./util/fetch"; import {addBaseURL, getIdFromSYProtocol, isSYProtocol, setNoteBook} from "./util/pathName"; -import {registerServiceWorker} from "./util/serviceWorker"; +import {registerServiceWorker, unregisterServiceWorker} from "./util/serviceWorker"; import {openFileById} from "./editor/util"; import { bootSync, @@ -161,7 +161,9 @@ export class App { await setProxy(); /// #if BROWSER - await registerServiceWorker(`${Constants.SERVICE_WORKER_PATH}?v=${Constants.SIYUAN_VERSION}`); + await registerServiceWorker(); + /// #else + await unregisterServiceWorker(); /// #endif addScriptSync(`${Constants.PROTYLE_CDN}/js/lute/lute.min.js?v=${Constants.SIYUAN_VERSION}`, "protyleLuteScript"); addScript(`${Constants.PROTYLE_CDN}/js/protyle-html.js?v=${Constants.SIYUAN_VERSION}`, "protyleWcHtmlScript"); diff --git a/app/src/mobile/index.ts b/app/src/mobile/index.ts index 764a884bbb8..6792bdb7ff5 100644 --- a/app/src/mobile/index.ts +++ b/app/src/mobile/index.ts @@ -20,7 +20,7 @@ import {getCurrentEditor, openMobileFileById} from "./editor"; import {getSearch} from "../util/functions"; import {initRightMenu} from "./menu"; import {openChangelog} from "../boot/openChangelog"; -import {registerServiceWorker} from "../util/serviceWorker"; +import {registerServiceWorker, unregisterServiceWorker} from "../util/serviceWorker"; import {afterLoadPlugin, loadPlugins} from "../plugin/loader"; import {saveScroll} from "../protyle/scroll/saveScroll"; import {removeBlock} from "../protyle/wysiwyg/remove"; @@ -83,7 +83,9 @@ class App { window.siyuan.config = confResponse.data.conf; if (!window.webkit?.messageHandlers && !window.JSAndroid) { - await registerServiceWorker(`${Constants.SERVICE_WORKER_PATH}?v=${Constants.SIYUAN_VERSION}`); + await registerServiceWorker(); + } else { + await unregisterServiceWorker(); } addScriptSync(`${Constants.PROTYLE_CDN}/js/lute/lute.min.js?v=${Constants.SIYUAN_VERSION}`, "protyleLuteScript"); addScript(`${Constants.PROTYLE_CDN}/js/protyle-html.js?v=${Constants.SIYUAN_VERSION}`, "protyleWcHtmlScript"); diff --git a/app/src/util/serviceWorker.ts b/app/src/util/serviceWorker.ts index 4b2201ba07f..dd3983a2eb2 100644 --- a/app/src/util/serviceWorker.ts +++ b/app/src/util/serviceWorker.ts @@ -1,18 +1,94 @@ +import { Constants } from "../constants"; + +const pathname = `${Constants.SERVICE_WORKER_PATH}?v=${Constants.SIYUAN_VERSION}`; + // https://github.com/siyuan-note/siyuan/pull/8012 -export const registerServiceWorker = async (scriptURL: string, scope = "/", workerType: WorkerType = "module") => { +export const registerServiceWorker = async ( + scirpt: string | URL = pathname, + scope: string = "/", + workerType: WorkerType = "module", +) => { if (("serviceWorker" in window.navigator) && ("caches" in window) && ("fetch" in window)) { try { // REF https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration - const registration = await window.navigator.serviceWorker.register(scriptURL, { + const registration = await window.navigator.serviceWorker.register(scirpt, { scope, type: workerType, }); await registration.update(); return true; } catch (error) { - console.debug(`Registration failed with ${error}`); - return false; + console.warn(`Registration service worker failed with ${error}`); } } return false; }; + +export const unregisterServiceWorker = async ( + scirpt: string | URL = pathname, + scope: string = "/", +) => { + if ("serviceWorker" in window.navigator) { + try { + const scriptURL = new URL(scirpt, window.document.baseURI); + const scopeURL = new URL(scope, window.document.baseURI); + + const registration = await window.navigator.serviceWorker.getRegistration(scope); + if (isTargetRegistration(scriptURL, scopeURL, registration)) { + const result = await registration.unregister(); + console.debug(`Unregistration service worker ${result ? "succeeded" : "failed"}`); + return result; + } + } catch (error) { + console.warn(`Unregistration service worker failed with ${error}`); + } + } + return false; +} + +/* ❗加载同一个 worker 时不会触发 */ +export const disableServiceWorker = ( + scirpt: string | URL = pathname, + scope: string = "/", +) => { + if ("serviceWorker" in window.navigator) { + try { + const scriptURL = new URL(scirpt, window.document.baseURI); + const scopeURL = new URL(scope, window.document.baseURI); + + const listener = async (e: Event) => { + console.debug(e); + const container = e.target as ServiceWorkerContainer; + const controllerScriptURL = new URL(container.controller.scriptURL); + if (scriptURL.pathname === controllerScriptURL.pathname) { + const registration = await container.ready; + if (isTargetRegistration(scriptURL, scopeURL, registration)) { + const result = await registration.unregister(); + console.debug(`Auto unregistration service worker ${result ? "succeeded" : "failed"}`); + } + } + }; + window.navigator.serviceWorker.addEventListener("controllerchange", listener); + return () => window.navigator.serviceWorker.removeEventListener("controllerchange", listener); + } catch (error) { + } + } + return () => {}; +} + +const isTargetRegistration = ( + scriptURL: URL, + scopeURL: URL, + registration: ServiceWorkerRegistration, +) => { + try { + if (registration?.active?.scriptURL && registration?.scope) { + const registrationScriptURL = new URL(registration.active.scriptURL); + const registrationScopeURL = new URL(registration.scope); + return scriptURL.pathname === registrationScriptURL.pathname + && scopeURL.pathname === registrationScopeURL.pathname; + } + } catch (error) { + } + return false +}