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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"use strict";
/**
* Class to handle service worker caching and request serving.
* @param {string} offlinePage - The URL of the page to show when offline.
* @param {boolean} debugMode - If true, debug information will be logged to the console.
*/
class ServiceWorkerManager {
/**
* Constructor for the ServiceWorkerManager class.
* @param {string} offlinePage - The URL of the page to show when offline.
* @param {boolean} debugMode - If true, debug information will be logged to the console.
*/
constructor(offlinePage, debugMode) {
/**
* Version of the cache used for cache management.
*/
this.CACHE_VERSION = 'v1';
/**
* Array of cache keys that the service worker should care about, used to keep track and delete old caches.
*/
this.CACHE_KEYS = [this.CACHE_VERSION];
/**
* The URL of the page to show when offline.
*/
this.offlinePage = offlinePage;
/**
* A boolean indicating if debug information should be logged to the console.
*/
this.debugMode = debugMode;
/**
* Initialize the service worker by setting up the event listeners.
*/
this.init();
}
/**
* Initialize the service worker by setting up event listeners for install, activate, fetch and message events.
*/
init() {
self.addEventListener("install", this.onInstall.bind(this));
self.addEventListener("activate", this.onActivate.bind(this));
self.addEventListener("fetch", this.onFetch.bind(this));
self.addEventListener('message', this.onMessage.bind(this));
}
/**
* Logs a message to the console if debug mode is enabled.
* @param {any} message - The message to log.
*/
debug(message) {
if (this.debugMode) {
console.log(message);
}
}
/**
* Event handler for the install event.
* Caches the offline page and forces the waiting service worker to become the active service worker.
* @param {InstallEvent} event - The install event.
*/
onInstall(event) {
this.debug("Installing Service Worker");
event.waitUntil(
this.cacheOfflinePage()
.then(() => self.skipWaiting())
.catch((error) => {
this.debug(`Install event error: ${error}`);
})
);
}
/**
* Event handler for the activate event.
* Clears old caches and takes control of all clients.
* @param {ExtendableEvent} event - The activate event.
*/
onActivate(event) {
this.debug("Activating Service Worker");
event.waitUntil(
this.clearOldCaches()
.then(() => self.clients.claim())
.catch((error) => {
this.debug(`Activate event error: ${error}`);
})
);
}
/**
* Event handler for the fetch event.
* Serves requests from the cache if possible, otherwise fetches from the network.
* Caches successful network responses.
* @param {FetchEvent} event - The fetch event.
*/
onFetch(event) {
// The rest of the fetch event handling code...
}
/**
* Event handler for the message event.
* Listens for a 'skipWaiting' message to call self.skipWaiting().
* @param {MessageEvent} event - The message event.
*/
onMessage(event) {
if (event.data.action === 'skipWaiting') {
self.skipWaiting();
}
}
/**
* Handle fetch errors, such as failing to retrieve a resource from the cache or network.
* For navigation requests, an offline page is shown.
* For image requests, an offline image is shown.
* @param {Request} request - The failed request.
* @param {Error} error - The error that caused the fetch to fail.
*/
handleFetchError(request, error) {
// The rest of the fetch error handling code...
}
/**
* Caches the offline page.
* @returns {Promise} - A promise that resolves once the offline page is cached.
*/
cacheOfflinePage() {
this.debug("Cache offline page");
return caches.open(this.CACHE_VERSION).then(cache =>
cache.addAll([this.offlinePage])
);
}
/**
* Deletes all caches that do not match the current cache version.
* @returns {Promise} - A promise that resolves once old caches are deleted.
*/
clearOldCaches() {
this.debug("Clean old caches");
return caches.keys().then(keys =>
Promise.all(keys.filter(key => !this.CACHE_KEYS.includes(key)).map(key => caches.delete(key)))
);
}
}
// Create an instance of the ServiceWorkerManager class.
new ServiceWorkerManager("/offline/index.html", false);