mirror of
https://github.com/owncast/owncast.git
synced 2026-03-13 09:51:16 +08:00
fix(js): merge all service worker logic into a single worker, and allow precaching to be cancelled
This commit is contained in:
@@ -13,7 +13,8 @@
|
||||
"i18n/index.js",
|
||||
"i18next-parser.config.mjs",
|
||||
"types/index.ts",
|
||||
"scripts/i18n-extract.js"
|
||||
"scripts/i18n-extract.js",
|
||||
"worker/**"
|
||||
],
|
||||
"ignoreDependencies": [
|
||||
"@fontsource/inter",
|
||||
|
||||
@@ -25,7 +25,6 @@ import { TitleNotifier } from '../../TitleNotifier/TitleNotifier';
|
||||
import { ServerRenderedHydration } from '../../ServerRendered/ServerRenderedHydration';
|
||||
import { Theme } from '../../theme/Theme';
|
||||
import styles from './Main.module.scss';
|
||||
import { PushNotificationServiceWorker } from '../../workers/PushNotificationServiceWorker/PushNotificationServiceWorker';
|
||||
import { AppStateOptions } from '../../stores/application-state';
|
||||
import { Noscript } from '../../ui/Noscript/Noscript';
|
||||
import { ServerStatus } from '../../../interfaces/server-status.model';
|
||||
@@ -96,7 +95,6 @@ export const Main: FC = () => {
|
||||
>
|
||||
<ClientConfigStore />
|
||||
</ErrorBoundary>
|
||||
<PushNotificationServiceWorker />
|
||||
<TitleNotifier name={name} />
|
||||
<Theme />
|
||||
<Script strategy="afterInteractive" src="/customjavascript" />
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
@@ -1,27 +0,0 @@
|
||||
/* eslint-disable react/no-danger */
|
||||
import { FC, useEffect } from 'react';
|
||||
|
||||
export const PushNotificationServiceWorker: FC = () => {
|
||||
const add = () => {
|
||||
navigator.serviceWorker.register('/serviceWorker.js').then(
|
||||
registration => {
|
||||
console.debug('Service Worker registration successful with scope: ', registration.scope);
|
||||
},
|
||||
err => {
|
||||
console.error('Service Worker registration failed: ', err);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', add);
|
||||
}
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('load', add);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -6,6 +6,7 @@ const { PHASE_DEVELOPMENT_SERVER } = require('next/constants');
|
||||
|
||||
const withPWA = require('next-pwa')({
|
||||
dest: 'public',
|
||||
customWorkerDir: 'worker',
|
||||
runtimeCaching: [],
|
||||
register: true,
|
||||
skipWaiting: true,
|
||||
|
||||
278
web/package-lock.json
generated
278
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
||||
/* eslint-disable no-restricted-globals */
|
||||
self.addEventListener('activate', event => {
|
||||
console.log('Owncast service worker activated', event);
|
||||
});
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
console.log('installing Owncast service worker...', event);
|
||||
});
|
||||
|
||||
self.addEventListener('push', event => {
|
||||
const data = JSON.parse(event.data.text());
|
||||
const { title, body, icon, tag } = data;
|
||||
const options = {
|
||||
title: title || 'Live!',
|
||||
body: body || 'This live stream has started.',
|
||||
icon: icon || '/logo/external',
|
||||
tag,
|
||||
};
|
||||
|
||||
event.waitUntil(self.registration.showNotification(options.title, options));
|
||||
});
|
||||
|
||||
self.addEventListener('notificationclick', event => {
|
||||
clients.openWindow('/');
|
||||
});
|
||||
@@ -27,7 +27,25 @@ function urlBase64ToUint8Array(base64String: string) {
|
||||
return outputArray;
|
||||
}
|
||||
|
||||
function pausePrecaching(): Promise<void> {
|
||||
return navigator.serviceWorker.ready.then(registration => {
|
||||
if (!registration.active) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise<void>(resolve => {
|
||||
const messageChannel = new MessageChannel();
|
||||
messageChannel.port1.onmessage = () => resolve();
|
||||
// Timeout fallback in case SW doesn't respond
|
||||
setTimeout(resolve, 100);
|
||||
registration.active.postMessage({ type: 'PAUSE_PRECACHING' }, [messageChannel.port2]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function registerWebPushNotifications(vapidPublicKey) {
|
||||
// Pause precaching to free up the service worker event loop
|
||||
await pausePrecaching();
|
||||
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
let subscription = await registration.pushManager.getSubscription();
|
||||
|
||||
|
||||
46
web/worker/index.js
Normal file
46
web/worker/index.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/* eslint-disable no-restricted-globals */
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
/* eslint-disable no-undef */
|
||||
|
||||
// Custom service worker code that next-pwa will bundle into sw.js.
|
||||
// This handles push notifications and provides a way to pause precaching
|
||||
// when notification registration needs priority.
|
||||
|
||||
// Handle messages from main thread
|
||||
self.addEventListener('message', event => {
|
||||
if (event.data?.type === 'PAUSE_PRECACHING') {
|
||||
console.log('Pausing precaching for notification registration');
|
||||
|
||||
// Signal to Workbox to stop precaching by clearing the queue
|
||||
// This works because Workbox checks this before each fetch
|
||||
if (self.__WB_MANIFEST) {
|
||||
// Clear the manifest to prevent further precaching
|
||||
self.__WB_MANIFEST.length = 0;
|
||||
}
|
||||
|
||||
// Respond that we're ready
|
||||
if (event.ports[0]) {
|
||||
event.ports[0].postMessage({ paused: true });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Push notification handler
|
||||
self.addEventListener('push', event => {
|
||||
const data = JSON.parse(event.data.text());
|
||||
const { title, body, icon, tag } = data;
|
||||
const options = {
|
||||
title: title || 'Live!',
|
||||
body: body || 'This live stream has started.',
|
||||
icon: icon || '/logo/external',
|
||||
tag,
|
||||
};
|
||||
|
||||
event.waitUntil(self.registration.showNotification(options.title, options));
|
||||
});
|
||||
|
||||
// Handle notification click
|
||||
self.addEventListener('notificationclick', event => {
|
||||
event.notification.close();
|
||||
event.waitUntil(clients.openWindow('/'));
|
||||
});
|
||||
Reference in New Issue
Block a user