-
Notifications
You must be signed in to change notification settings - Fork 276
/
service-manager.ts
116 lines (97 loc) · 3.82 KB
/
service-manager.ts
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { PromiseDelegate } from '@lumino/coreutils';
import { ISignal, Signal } from '@lumino/signaling';
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
import { IServiceWorkerManager, WORKER_NAME } from './tokens';
const VERSION = PageConfig.getOption('appVersion');
export class ServiceWorkerManager implements IServiceWorkerManager {
constructor(options?: IServiceWorkerManager.IOptions) {
const workerUrl =
options?.workerUrl ?? URLExt.join(PageConfig.getBaseUrl(), WORKER_NAME);
const fullWorkerUrl = new URL(workerUrl, window.location.href);
const enableCache = PageConfig.getOption('enableServiceWorkerCache') || 'false';
fullWorkerUrl.searchParams.set('enableCache', enableCache);
void this.initialize(fullWorkerUrl.href).catch(console.warn);
}
/**
* A signal emitted when the registration changes.
*/
get registrationChanged(): ISignal<
IServiceWorkerManager,
ServiceWorkerRegistration | null
> {
return this._registrationChanged;
}
/**
* Whether the ServiceWorker is enabled or not.
*/
get enabled(): boolean {
return this._registration !== null;
}
get ready(): Promise<void> {
return this._ready.promise;
}
private unregisterOldServiceWorkers = (scriptURL: string) => {
const versionKey = `${scriptURL}-version`;
// Check if we have an installed version. If we do, compare it to the current version
// and unregister all service workers if they are different.
const installedVersion = localStorage.getItem(versionKey);
if ((installedVersion && installedVersion !== VERSION) || !installedVersion) {
// eslint-disable-next-line no-console
console.info('New version, unregistering existing service workers.');
navigator.serviceWorker
.getRegistrations()
.then((registrations) => {
for (const registration of registrations) {
registration.unregister();
}
})
.then(() => {
// eslint-disable-next-line no-console
console.info('All existing service workers have been unregistered.');
});
}
localStorage.setItem(versionKey, VERSION);
};
private async initialize(workerUrl: string): Promise<void> {
const { serviceWorker } = navigator;
let registration: ServiceWorkerRegistration | null = null;
if (!serviceWorker) {
console.warn('ServiceWorkers not supported in this browser');
} else if (serviceWorker.controller) {
const scriptURL = serviceWorker.controller.scriptURL;
this.unregisterOldServiceWorkers(scriptURL);
registration = (await serviceWorker.getRegistration(scriptURL)) || null;
// eslint-disable-next-line no-console
console.info('JupyterLite ServiceWorker was already registered');
}
if (!registration && serviceWorker) {
try {
// eslint-disable-next-line no-console
console.info('Registering new JupyterLite ServiceWorker', workerUrl);
registration = await serviceWorker.register(workerUrl);
// eslint-disable-next-line no-console
console.info('JupyterLite ServiceWorker was sucessfully registered');
} catch (err: any) {
console.warn(err);
console.warn(
`JupyterLite ServiceWorker registration unexpectedly failed: ${err}`,
);
}
}
this._setRegistration(registration);
if (!registration) {
this._ready.reject(void 0);
} else {
this._ready.resolve(void 0);
}
}
private _setRegistration(registration: ServiceWorkerRegistration | null) {
this._registration = registration;
this._registrationChanged.emit(this._registration);
}
private _registration: ServiceWorkerRegistration | null = null;
private _registrationChanged = new Signal<this, ServiceWorkerRegistration | null>(
this,
);
private _ready = new PromiseDelegate<void>();
}