Repository navigation
Expand file tree
/
Copy pathserviceWorker.js
More file actions
57 lines (51 loc) · 2.5 KB
/
Copy pathserviceWorker.js
File metadata and controls
57 lines (51 loc) · 2.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Registers public/sw.js, the service worker that makes Spellbook installable and gives
// a page load with no network the /offline/ page. What the worker does and does not do
// is written at the top of that file.
//
// It is registered from here, in the bundle, rather than from a script in index.html,
// because the page CSP (public/_headers) allows no inline script.
/** Where the worker is served from: the site root, so its scope is the whole origin. */
export const SERVICE_WORKER_URL = '/sw.js';
/**
* Register the service worker once the page has loaded, so it never competes with the
* app's first render. Returns whether a registration was started.
*
* It does nothing:
* - outside a production build: the dev server would otherwise be served from a
* worker's idea of the page;
* - without `navigator.serviceWorker`, which browsers expose only on https or
* localhost, so a plain-http LAN address quietly stays an ordinary web page;
* - inside the iOS and Android shells (apps/ios, apps/android). They load this same
* bundle from the app itself, which already works offline, and a worker there
* would sit between the WebView and its bundled files for no gain.
*
* It never throws. The site is an ordinary web page without the worker, so nothing here
* may be what stops the app from starting. Reading `navigator.serviceWorker` can throw
* (Chrome 156 raises a SecurityError for a document sandboxed, by a CSP `sandbox` header,
* without `allow-same-origin`; other browsers were not tried), and so can `register()`.
* Both are caught.
*
* @param {{ production?: boolean, win?: Window & typeof globalThis }} [options] injected by tests
*/
export function registerServiceWorker({ production = import.meta.env.PROD, win = window } = {}) {
if (!production) return false;
// Not worth interrupting the reader or the crash-report budget for.
const skip = (/** @type {unknown} */ err) => console.warn('Spellbook: could not register the service worker', err);
try {
if (!('serviceWorker' in win.navigator)) return false;
if (/** @type {any} */ (win).Capacitor?.isNativePlatform?.()) return false;
const register = () => {
try {
win.navigator.serviceWorker.register(SERVICE_WORKER_URL, { scope: '/' }).catch(skip);
} catch (err) {
skip(err);
}
};
if (win.document.readyState === 'complete') register();
else win.addEventListener('load', register, { once: true });
return true;
} catch (err) {
skip(err);
return false;
}
}