@vite-pwa/workbox-window 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/README.md +80 -0
- package/dist/index.cjs +583 -0
- package/dist/index.d.cts +373 -0
- package/dist/index.d.ts +373 -0
- package/dist/index.js +554 -0
- package/package.json +57 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
// src/messageSW.ts
|
|
2
|
+
function messageSW(sw, data) {
|
|
3
|
+
return new Promise((resolve) => {
|
|
4
|
+
const messageChannel = new MessageChannel();
|
|
5
|
+
messageChannel.port1.onmessage = (event) => {
|
|
6
|
+
resolve(event.data);
|
|
7
|
+
};
|
|
8
|
+
sw.postMessage(data, [messageChannel.port2]);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// src/utils/dontWaitFor.ts
|
|
13
|
+
function dontWaitFor(promise) {
|
|
14
|
+
void promise.then(() => {
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/utils/logger.ts
|
|
19
|
+
var logger = process.env.NODE_ENV === "production" ? null : (() => {
|
|
20
|
+
if (!("__WB_DISABLE_DEV_LOGS" in globalThis))
|
|
21
|
+
self.__WB_DISABLE_DEV_LOGS = false;
|
|
22
|
+
let inGroup = false;
|
|
23
|
+
const methodToColorMap = {
|
|
24
|
+
debug: "#7f8c8d",
|
|
25
|
+
// Gray
|
|
26
|
+
log: "#2ecc71",
|
|
27
|
+
// Green
|
|
28
|
+
warn: "#f39c12",
|
|
29
|
+
// Yellow
|
|
30
|
+
error: "#c0392b",
|
|
31
|
+
// Red
|
|
32
|
+
groupCollapsed: "#3498db",
|
|
33
|
+
// Blue
|
|
34
|
+
groupEnd: null
|
|
35
|
+
// No colored prefix on groupEnd
|
|
36
|
+
};
|
|
37
|
+
const print = function(method, args) {
|
|
38
|
+
if (self.__WB_DISABLE_DEV_LOGS)
|
|
39
|
+
return;
|
|
40
|
+
if (method === "groupCollapsed") {
|
|
41
|
+
if (typeof navigator !== "undefined" && /^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
|
|
42
|
+
console[method](...args);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const styles = [
|
|
47
|
+
`background: ${methodToColorMap[method]}`,
|
|
48
|
+
"border-radius: 0.5em",
|
|
49
|
+
"color: white",
|
|
50
|
+
"font-weight: bold",
|
|
51
|
+
"padding: 2px 0.5em"
|
|
52
|
+
];
|
|
53
|
+
const logPrefix = inGroup ? [] : ["%c@vite-pwa/workbox-window", styles.join(";")];
|
|
54
|
+
console[method](...logPrefix, ...args);
|
|
55
|
+
if (method === "groupCollapsed")
|
|
56
|
+
inGroup = true;
|
|
57
|
+
if (method === "groupEnd")
|
|
58
|
+
inGroup = false;
|
|
59
|
+
};
|
|
60
|
+
const api = {};
|
|
61
|
+
const loggerMethods = Object.keys(methodToColorMap);
|
|
62
|
+
for (const key of loggerMethods) {
|
|
63
|
+
const method = key;
|
|
64
|
+
api[method] = (...args) => {
|
|
65
|
+
print(method, args);
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return api;
|
|
69
|
+
})();
|
|
70
|
+
|
|
71
|
+
// src/utils/Deferred.ts
|
|
72
|
+
var Deferred = class {
|
|
73
|
+
promise;
|
|
74
|
+
resolve;
|
|
75
|
+
reject;
|
|
76
|
+
/**
|
|
77
|
+
* Creates a promise and exposes its resolve and reject functions as methods.
|
|
78
|
+
*/
|
|
79
|
+
constructor() {
|
|
80
|
+
this.promise = new Promise((resolve, reject) => {
|
|
81
|
+
this.resolve = resolve;
|
|
82
|
+
this.reject = reject;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// src/utils/WorkboxEventTarget.ts
|
|
88
|
+
var WorkboxEventTarget = class {
|
|
89
|
+
_eventListenerRegistry = /* @__PURE__ */ new Map();
|
|
90
|
+
/**
|
|
91
|
+
* @param {string} type
|
|
92
|
+
* @param {Function} listener
|
|
93
|
+
* @private
|
|
94
|
+
*/
|
|
95
|
+
addEventListener(type, listener) {
|
|
96
|
+
const foo = this._getEventListenersByType(type);
|
|
97
|
+
foo.add(listener);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* @param {string} type
|
|
101
|
+
* @param {Function} listener
|
|
102
|
+
* @private
|
|
103
|
+
*/
|
|
104
|
+
removeEventListener(type, listener) {
|
|
105
|
+
this._getEventListenersByType(type).delete(listener);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* @param {object} event
|
|
109
|
+
* @private
|
|
110
|
+
*/
|
|
111
|
+
dispatchEvent(event) {
|
|
112
|
+
event.target = this;
|
|
113
|
+
const listeners = this._getEventListenersByType(event.type);
|
|
114
|
+
for (const listener of listeners)
|
|
115
|
+
listener(event);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Returns a Set of listeners associated with the passed event type.
|
|
119
|
+
* If no handlers have been registered, an empty Set is returned.
|
|
120
|
+
*
|
|
121
|
+
* @param {string} type The event type.
|
|
122
|
+
* @return {Set<ListenerCallback>} An array of handler functions.
|
|
123
|
+
* @private
|
|
124
|
+
*/
|
|
125
|
+
_getEventListenersByType(type) {
|
|
126
|
+
if (!this._eventListenerRegistry.has(type))
|
|
127
|
+
this._eventListenerRegistry.set(type, /* @__PURE__ */ new Set());
|
|
128
|
+
return this._eventListenerRegistry.get(type);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// src/utils/urlsMatch.ts
|
|
133
|
+
function urlsMatch(url1, url2) {
|
|
134
|
+
const { href } = location;
|
|
135
|
+
return new URL(url1, href).href === new URL(url2, href).href;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/utils/WorkboxEvent.ts
|
|
139
|
+
var WorkboxEvent = class {
|
|
140
|
+
constructor(type, props) {
|
|
141
|
+
this.type = type;
|
|
142
|
+
Object.assign(this, props);
|
|
143
|
+
}
|
|
144
|
+
target;
|
|
145
|
+
sw;
|
|
146
|
+
originalEvent;
|
|
147
|
+
isExternal;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// src/Workbox.ts
|
|
151
|
+
var WAITING_TIMEOUT_DURATION = 200;
|
|
152
|
+
var REGISTRATION_TIMEOUT_DURATION = 6e4;
|
|
153
|
+
var SKIP_WAITING_MESSAGE = { type: "SKIP_WAITING" };
|
|
154
|
+
var Workbox = class extends WorkboxEventTarget {
|
|
155
|
+
_scriptURL;
|
|
156
|
+
_registerOptions = {};
|
|
157
|
+
_updateFoundCount = 0;
|
|
158
|
+
// Deferreds we can resolve later.
|
|
159
|
+
_swDeferred = new Deferred();
|
|
160
|
+
_activeDeferred = new Deferred();
|
|
161
|
+
_controllingDeferred = new Deferred();
|
|
162
|
+
_registrationTime = 0;
|
|
163
|
+
_isUpdate;
|
|
164
|
+
_compatibleControllingSW;
|
|
165
|
+
_registration;
|
|
166
|
+
_sw;
|
|
167
|
+
_ownSWs = /* @__PURE__ */ new Set();
|
|
168
|
+
_externalSW;
|
|
169
|
+
_waitingTimeout;
|
|
170
|
+
/**
|
|
171
|
+
* Creates a new Workbox instance with a script URL and service worker
|
|
172
|
+
* options. The script URL and options are the same as those used when
|
|
173
|
+
* calling [navigator.serviceWorker.register(scriptURL, options)](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register).
|
|
174
|
+
*
|
|
175
|
+
* @param {string|TrustedScriptURL} scriptURL The service worker script
|
|
176
|
+
* associated with this instance. Using a
|
|
177
|
+
* [`TrustedScriptURL`](https://web.dev/trusted-types/) is supported.
|
|
178
|
+
* @param {object} [registerOptions] The service worker options associated
|
|
179
|
+
* with this instance.
|
|
180
|
+
*/
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
182
|
+
constructor(scriptURL, registerOptions = {}) {
|
|
183
|
+
super();
|
|
184
|
+
this._scriptURL = scriptURL;
|
|
185
|
+
this._registerOptions = registerOptions;
|
|
186
|
+
navigator.serviceWorker.addEventListener("message", this._onMessage);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Registers a service worker for this instances script URL and service
|
|
190
|
+
* worker options. By default this method delays registration until after
|
|
191
|
+
* the window has loaded.
|
|
192
|
+
*
|
|
193
|
+
* @param {object} [options]
|
|
194
|
+
* @param {Function} [options.immediate] Setting this to true will
|
|
195
|
+
* register the service worker immediately, even if the window has
|
|
196
|
+
* not loaded (not recommended).
|
|
197
|
+
*/
|
|
198
|
+
async register({ immediate = false } = {}) {
|
|
199
|
+
if (process.env.NODE_ENV !== "production") {
|
|
200
|
+
if (this._registrationTime) {
|
|
201
|
+
logger.error(
|
|
202
|
+
"Cannot re-register a Workbox instance after it has been registered. Create a new instance instead."
|
|
203
|
+
);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (!immediate && document.readyState !== "complete")
|
|
208
|
+
await new Promise((resolve) => window.addEventListener("load", resolve));
|
|
209
|
+
this._isUpdate = Boolean(navigator.serviceWorker.controller);
|
|
210
|
+
this._compatibleControllingSW = this._getControllingSWIfCompatible();
|
|
211
|
+
this._registration = await this._registerScript();
|
|
212
|
+
if (this._compatibleControllingSW) {
|
|
213
|
+
this._sw = this._compatibleControllingSW;
|
|
214
|
+
this._activeDeferred.resolve(this._compatibleControllingSW);
|
|
215
|
+
this._controllingDeferred.resolve(this._compatibleControllingSW);
|
|
216
|
+
this._compatibleControllingSW.addEventListener(
|
|
217
|
+
"statechange",
|
|
218
|
+
this._onStateChange,
|
|
219
|
+
{ once: true }
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
const waitingSW = this._registration.waiting;
|
|
223
|
+
if (waitingSW && urlsMatch(waitingSW.scriptURL, this._scriptURL.toString())) {
|
|
224
|
+
this._sw = waitingSW;
|
|
225
|
+
dontWaitFor(
|
|
226
|
+
Promise.resolve().then(() => {
|
|
227
|
+
this.dispatchEvent(
|
|
228
|
+
new WorkboxEvent("waiting", {
|
|
229
|
+
sw: waitingSW,
|
|
230
|
+
wasWaitingBeforeRegister: true
|
|
231
|
+
})
|
|
232
|
+
);
|
|
233
|
+
if (process.env.NODE_ENV !== "production") {
|
|
234
|
+
logger.warn(
|
|
235
|
+
"A service worker was already waiting to activate before this script was registered..."
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
if (this._sw) {
|
|
242
|
+
this._swDeferred.resolve(this._sw);
|
|
243
|
+
this._ownSWs.add(this._sw);
|
|
244
|
+
}
|
|
245
|
+
if (process.env.NODE_ENV !== "production") {
|
|
246
|
+
logger.log(
|
|
247
|
+
"Successfully registered service worker.",
|
|
248
|
+
this._scriptURL.toString()
|
|
249
|
+
);
|
|
250
|
+
if (navigator.serviceWorker.controller) {
|
|
251
|
+
if (this._compatibleControllingSW) {
|
|
252
|
+
logger.debug(
|
|
253
|
+
"A service worker with the same script URL is already controlling this page."
|
|
254
|
+
);
|
|
255
|
+
} else {
|
|
256
|
+
logger.debug(
|
|
257
|
+
"A service worker with a different script URL is currently controlling the page. The browser is now fetching the new script now..."
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const currentPageIsOutOfScope = () => {
|
|
262
|
+
const scopeURL = new URL(
|
|
263
|
+
this._registerOptions.scope || this._scriptURL.toString(),
|
|
264
|
+
document.baseURI
|
|
265
|
+
);
|
|
266
|
+
const scopeURLBasePath = new URL("./", scopeURL.href).pathname;
|
|
267
|
+
return !location.pathname.startsWith(scopeURLBasePath);
|
|
268
|
+
};
|
|
269
|
+
if (currentPageIsOutOfScope()) {
|
|
270
|
+
logger.warn(
|
|
271
|
+
"The current page is not in scope for the registered service worker. Was this a mistake?"
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
this._registration.addEventListener("updatefound", this._onUpdateFound);
|
|
276
|
+
navigator.serviceWorker.addEventListener(
|
|
277
|
+
"controllerchange",
|
|
278
|
+
this._onControllerChange
|
|
279
|
+
);
|
|
280
|
+
return this._registration;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Checks for updates of the registered service worker.
|
|
284
|
+
*/
|
|
285
|
+
async update() {
|
|
286
|
+
if (!this._registration) {
|
|
287
|
+
if (process.env.NODE_ENV !== "production") {
|
|
288
|
+
logger.error(
|
|
289
|
+
"Cannot update a Workbox instance without being registered. Register the Workbox instance first."
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
await this._registration.update();
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Resolves to the service worker registered by this instance as soon as it
|
|
298
|
+
* is active. If a service worker was already controlling at registration
|
|
299
|
+
* time then it will resolve to that if the script URLs (and optionally
|
|
300
|
+
* script versions) match, otherwise it will wait until an update is found
|
|
301
|
+
* and activates.
|
|
302
|
+
*
|
|
303
|
+
* @return {Promise<ServiceWorker>}
|
|
304
|
+
*/
|
|
305
|
+
get active() {
|
|
306
|
+
return this._activeDeferred.promise;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Resolves to the service worker registered by this instance as soon as it
|
|
310
|
+
* is controlling the page. If a service worker was already controlling at
|
|
311
|
+
* registration time then it will resolve to that if the script URLs (and
|
|
312
|
+
* optionally script versions) match, otherwise it will wait until an update
|
|
313
|
+
* is found and starts controlling the page.
|
|
314
|
+
* Note: the first time a service worker is installed it will active but
|
|
315
|
+
* not start controlling the page unless `clients.claim()` is called in the
|
|
316
|
+
* service worker.
|
|
317
|
+
*
|
|
318
|
+
* @return {Promise<ServiceWorker>}
|
|
319
|
+
*/
|
|
320
|
+
get controlling() {
|
|
321
|
+
return this._controllingDeferred.promise;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Resolves with a reference to a service worker that matches the script URL
|
|
325
|
+
* of this instance, as soon as it's available.
|
|
326
|
+
*
|
|
327
|
+
* If, at registration time, there's already an active or waiting service
|
|
328
|
+
* worker with a matching script URL, it will be used (with the waiting
|
|
329
|
+
* service worker taking precedence over the active service worker if both
|
|
330
|
+
* match, since the waiting service worker would have been registered more
|
|
331
|
+
* recently).
|
|
332
|
+
* If there's no matching active or waiting service worker at registration
|
|
333
|
+
* time then the promise will not resolve until an update is found and starts
|
|
334
|
+
* installing, at which point the installing service worker is used.
|
|
335
|
+
*
|
|
336
|
+
* @return {Promise<ServiceWorker>}
|
|
337
|
+
*/
|
|
338
|
+
getSW() {
|
|
339
|
+
return this._sw !== void 0 ? Promise.resolve(this._sw) : this._swDeferred.promise;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Sends the passed data object to the service worker registered by this
|
|
343
|
+
* instance (via {@link workbox-window.Workbox#getSW}) and resolves
|
|
344
|
+
* with a response (if any).
|
|
345
|
+
*
|
|
346
|
+
* A response can be set in a message handler in the service worker by
|
|
347
|
+
* calling `event.ports[0].postMessage(...)`, which will resolve the promise
|
|
348
|
+
* returned by `messageSW()`. If no response is set, the promise will never
|
|
349
|
+
* resolve.
|
|
350
|
+
*
|
|
351
|
+
* @param {object} data An object to send to the service worker
|
|
352
|
+
* @return {Promise<object>}
|
|
353
|
+
*/
|
|
354
|
+
// We might be able to change the 'data' type to Record<string, unknown> in the future.
|
|
355
|
+
async messageSW(data) {
|
|
356
|
+
const sw = await this.getSW();
|
|
357
|
+
return messageSW(sw, data);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Sends a `{type: 'SKIP_WAITING'}` message to the service worker that's
|
|
361
|
+
* currently in the `waiting` state associated with the current registration.
|
|
362
|
+
*
|
|
363
|
+
* If there is no current registration or no service worker is `waiting`,
|
|
364
|
+
* calling this will have no effect.
|
|
365
|
+
*/
|
|
366
|
+
messageSkipWaiting() {
|
|
367
|
+
if (this._registration && this._registration.waiting)
|
|
368
|
+
void messageSW(this._registration.waiting, SKIP_WAITING_MESSAGE);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Checks for a service worker already controlling the page and returns
|
|
372
|
+
* it if its script URL matches.
|
|
373
|
+
*
|
|
374
|
+
* @private
|
|
375
|
+
* @return {ServiceWorker|undefined}
|
|
376
|
+
*/
|
|
377
|
+
_getControllingSWIfCompatible() {
|
|
378
|
+
const controller = navigator.serviceWorker.controller;
|
|
379
|
+
if (controller && urlsMatch(controller.scriptURL, this._scriptURL.toString()))
|
|
380
|
+
return controller;
|
|
381
|
+
else
|
|
382
|
+
return void 0;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Registers a service worker for this instances script URL and register
|
|
386
|
+
* options and tracks the time registration was complete.
|
|
387
|
+
*
|
|
388
|
+
* @private
|
|
389
|
+
*/
|
|
390
|
+
async _registerScript() {
|
|
391
|
+
try {
|
|
392
|
+
const reg = await navigator.serviceWorker.register(
|
|
393
|
+
this._scriptURL,
|
|
394
|
+
this._registerOptions
|
|
395
|
+
);
|
|
396
|
+
this._registrationTime = performance.now();
|
|
397
|
+
return reg;
|
|
398
|
+
} catch (error) {
|
|
399
|
+
if (process.env.NODE_ENV !== "production")
|
|
400
|
+
logger.error(error);
|
|
401
|
+
throw error;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* @private
|
|
406
|
+
*/
|
|
407
|
+
_onUpdateFound = (originalEvent) => {
|
|
408
|
+
const registration = this._registration;
|
|
409
|
+
const installingSW = registration.installing;
|
|
410
|
+
const updateLikelyTriggeredExternally = !!(this._updateFoundCount > 0 || !urlsMatch(installingSW.scriptURL, this._scriptURL.toString()) || performance.now() > this._registrationTime + REGISTRATION_TIMEOUT_DURATION);
|
|
411
|
+
if (updateLikelyTriggeredExternally) {
|
|
412
|
+
this._externalSW = installingSW;
|
|
413
|
+
registration.removeEventListener("updatefound", this._onUpdateFound);
|
|
414
|
+
} else {
|
|
415
|
+
this._sw = installingSW;
|
|
416
|
+
this._ownSWs.add(installingSW);
|
|
417
|
+
this._swDeferred.resolve(installingSW);
|
|
418
|
+
if (process.env.NODE_ENV !== "production") {
|
|
419
|
+
if (navigator.serviceWorker.controller)
|
|
420
|
+
logger.log("Updated service worker found. Installing now...");
|
|
421
|
+
else
|
|
422
|
+
logger.log("Service worker is installing...");
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
this.dispatchEvent(
|
|
426
|
+
new WorkboxEvent("installing", {
|
|
427
|
+
sw: installingSW,
|
|
428
|
+
originalEvent,
|
|
429
|
+
isExternal: updateLikelyTriggeredExternally,
|
|
430
|
+
isUpdate: this._isUpdate
|
|
431
|
+
})
|
|
432
|
+
);
|
|
433
|
+
++this._updateFoundCount;
|
|
434
|
+
installingSW.addEventListener("statechange", this._onStateChange);
|
|
435
|
+
};
|
|
436
|
+
/**
|
|
437
|
+
* @private
|
|
438
|
+
* @param {Event} originalEvent
|
|
439
|
+
*/
|
|
440
|
+
_onStateChange = (originalEvent) => {
|
|
441
|
+
const registration = this._registration;
|
|
442
|
+
const sw = originalEvent.target;
|
|
443
|
+
const { state } = sw;
|
|
444
|
+
const isExternal = sw === this._externalSW;
|
|
445
|
+
const eventProps = {
|
|
446
|
+
sw,
|
|
447
|
+
isExternal,
|
|
448
|
+
originalEvent
|
|
449
|
+
};
|
|
450
|
+
if (!isExternal && this._isUpdate)
|
|
451
|
+
eventProps.isUpdate = true;
|
|
452
|
+
this.dispatchEvent(
|
|
453
|
+
new WorkboxEvent(state, eventProps)
|
|
454
|
+
);
|
|
455
|
+
if (state === "installed") {
|
|
456
|
+
this._waitingTimeout = self.setTimeout(() => {
|
|
457
|
+
if (state === "installed" && registration.waiting === sw) {
|
|
458
|
+
this.dispatchEvent(new WorkboxEvent("waiting", eventProps));
|
|
459
|
+
if (process.env.NODE_ENV !== "production") {
|
|
460
|
+
if (isExternal) {
|
|
461
|
+
logger.warn(
|
|
462
|
+
"An external service worker has installed but is waiting for this client to close before activating..."
|
|
463
|
+
);
|
|
464
|
+
} else {
|
|
465
|
+
logger.warn(
|
|
466
|
+
"The service worker has installed but is waiting for existing clients to close before activating..."
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}, WAITING_TIMEOUT_DURATION);
|
|
472
|
+
} else if (state === "activating") {
|
|
473
|
+
clearTimeout(this._waitingTimeout);
|
|
474
|
+
if (!isExternal)
|
|
475
|
+
this._activeDeferred.resolve(sw);
|
|
476
|
+
}
|
|
477
|
+
if (process.env.NODE_ENV !== "production") {
|
|
478
|
+
switch (state) {
|
|
479
|
+
case "installed":
|
|
480
|
+
if (isExternal) {
|
|
481
|
+
logger.warn(
|
|
482
|
+
"An external service worker has installed. You may want to suggest users reload this page."
|
|
483
|
+
);
|
|
484
|
+
} else {
|
|
485
|
+
logger.log("Registered service worker installed.");
|
|
486
|
+
}
|
|
487
|
+
break;
|
|
488
|
+
case "activated":
|
|
489
|
+
if (isExternal) {
|
|
490
|
+
logger.warn("An external service worker has activated.");
|
|
491
|
+
} else {
|
|
492
|
+
logger.log("Registered service worker activated.");
|
|
493
|
+
if (sw !== navigator.serviceWorker.controller) {
|
|
494
|
+
logger.warn(
|
|
495
|
+
"The registered service worker is active but not yet controlling the page. Reload or run `clients.claim()` in the service worker."
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
break;
|
|
500
|
+
case "redundant":
|
|
501
|
+
if (sw === this._compatibleControllingSW)
|
|
502
|
+
logger.log("Previously controlling service worker now redundant!");
|
|
503
|
+
else if (!isExternal)
|
|
504
|
+
logger.log("Registered service worker now redundant!");
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
/**
|
|
510
|
+
* @private
|
|
511
|
+
* @param {Event} originalEvent
|
|
512
|
+
*/
|
|
513
|
+
_onControllerChange = (originalEvent) => {
|
|
514
|
+
const sw = this._sw;
|
|
515
|
+
const isExternal = sw !== navigator.serviceWorker.controller;
|
|
516
|
+
this.dispatchEvent(
|
|
517
|
+
new WorkboxEvent("controlling", {
|
|
518
|
+
isExternal,
|
|
519
|
+
originalEvent,
|
|
520
|
+
sw,
|
|
521
|
+
isUpdate: this._isUpdate
|
|
522
|
+
})
|
|
523
|
+
);
|
|
524
|
+
if (!isExternal) {
|
|
525
|
+
if (process.env.NODE_ENV !== "production")
|
|
526
|
+
logger.log("Registered service worker now controlling this page.");
|
|
527
|
+
this._controllingDeferred.resolve(sw);
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
/**
|
|
531
|
+
* @private
|
|
532
|
+
* @param {Event} originalEvent
|
|
533
|
+
*/
|
|
534
|
+
_onMessage = async (originalEvent) => {
|
|
535
|
+
const { data, ports, source } = originalEvent;
|
|
536
|
+
await this.getSW();
|
|
537
|
+
if (this._ownSWs.has(source)) {
|
|
538
|
+
this.dispatchEvent(
|
|
539
|
+
new WorkboxEvent("message", {
|
|
540
|
+
// Can't change type 'any' of data.
|
|
541
|
+
data,
|
|
542
|
+
originalEvent,
|
|
543
|
+
ports,
|
|
544
|
+
sw: source
|
|
545
|
+
})
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
};
|
|
550
|
+
export {
|
|
551
|
+
Workbox,
|
|
552
|
+
WorkboxEvent,
|
|
553
|
+
messageSW
|
|
554
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vite-pwa/workbox-window",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "8.0.0",
|
|
5
|
+
"packageManager": "pnpm@8.13.1",
|
|
6
|
+
"description": "Simplifies communications with Workbox packages running in the service worker",
|
|
7
|
+
"author": "Google's Web DevRel Team, Vite PWA's Team",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"funding": "https://github.com/sponsors/antfu",
|
|
10
|
+
"homepage": "https://github.com/vite-pwa/workbox-window-es#readme",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/vite-pwa/workbox-window-es.git"
|
|
14
|
+
},
|
|
15
|
+
"bugs": "https://github.com/vite-pwa/workbox-window-es/issues",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"workbox",
|
|
18
|
+
"workboxjs",
|
|
19
|
+
"service worker",
|
|
20
|
+
"sw",
|
|
21
|
+
"window",
|
|
22
|
+
"message",
|
|
23
|
+
"postMessage"
|
|
24
|
+
],
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"import": "./dist/index.js",
|
|
29
|
+
"require": "./dist/index.cjs"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"main": "dist/index.cjs",
|
|
33
|
+
"module": "dist/index.js",
|
|
34
|
+
"types": "dist/index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsup src/index.ts --dts --target esnext --format esm,cjs",
|
|
40
|
+
"lint": "eslint .",
|
|
41
|
+
"lint-fix": "nr lint --fix",
|
|
42
|
+
"prepublishOnly": "npm run build",
|
|
43
|
+
"release": "bumpp && npm publish --access=public"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@antfu/eslint-config": "^0.43.1",
|
|
48
|
+
"@antfu/ni": "^0.21.12",
|
|
49
|
+
"@types/node": "^18.15.3",
|
|
50
|
+
"@types/trusted-types": "^2.0.7",
|
|
51
|
+
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
|
52
|
+
"bumpp": "^9.2.0",
|
|
53
|
+
"eslint": "^8.55.0",
|
|
54
|
+
"tsup": "^8.0.1",
|
|
55
|
+
"typescript": "^5.3.3"
|
|
56
|
+
}
|
|
57
|
+
}
|