Skip to content

Commit 7f6d1f7

Browse files
committed
Service Worker TS!
Rewrote the Service Worker in TypeScript! It *kind of* works great, but not quite. I wish the TypeScript team made tooling for Workers a bit better, as it seems harder to work with than it should be. This rewrite was all from last night, and it took a few hours to learn how to get things right (I didn't get around to commiting it until now though). There aren't any type errors anymore, but I'm also unsure if it will run sucessfully yet. I don't have a device/OS to test the Web Share Target API support anymore, since my Chromebook runs Ubuntu now :) While it's not fully functional yet, this is a step in the right direction for type-safe Service Worker code! I mostly rewrote it with my new programming styles, expanding things out for readability, and making use of async-await where it was previously just `.then()` calls and such. Some help to get it working: https://github.com/NicholasPeretti/service-worker-ts-example https://stackoverflow.com/questions/89332/how-do-i-recover-a-dropped-stash-in-git (I had an oopsie XD) Edit: Tried testing out the worker in the browser, and modern TypeScript now includes empty `export {}` instances in the resulting JS, which breaks declaring the file as a module, as you can't have `export {}` in a non-module script. The only way I got close to this was to name the file `.mts`, but I'm not sure if I like that or not. But hey, it may work. With that being a possible solution, I found all of these sources along the way also: https://stackoverflow.com/questions/56356655/structuring-a-typescript-project-with-workers https://github.com/jakearchibald/typescript-worker-example (now outdated, unfortunately, thanks to this new TypeScript change) microsoft/TypeScript#41513 https://www.devextent.com/create-service-worker-typescript/ (almost works! falls down to the same issue sadly) microsoft/TypeScript#14877 microsoft/TypeScript#11781
1 parent 441d180 commit 7f6d1f7

File tree

1 file changed

+98
-37
lines changed

1 file changed

+98
-37
lines changed

service-worker.ts

+98-37
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,118 @@
1-
self.Editor = {
1+
/// <reference no-default-lib="true"/>
2+
/// <reference lib="ESNext"/>
3+
/// <reference lib="WebWorker"/>
4+
5+
declare global {
6+
interface WorkerNavigator {
7+
standalone?: boolean;
8+
userAgentData?: NavigatorUAData;
9+
}
10+
11+
interface NavigatorUAData {
12+
platform: string;
13+
}
14+
}
15+
16+
declare var self: ServiceWorkerGlobalScope;
17+
18+
export {};
19+
20+
const STE = {
221
version: "Smart Text Editor v4.0.0",
322
cache: true,
4-
environment: () => ({
5-
macOS_device: (/(macOS|Mac)/i.test(("userAgentData" in navigator) ? navigator.userAgentData.platform : navigator.platform) && navigator.standalone === undefined)
6-
}),
7-
share_files: []
23+
environment: {
24+
get macOSDevice() {
25+
return (/(macOS|Mac)/i.test(navigator.userAgentData?.platform || navigator.platform) && navigator.standalone === undefined);
26+
}
27+
},
28+
shareFiles: [] as File[]
829
}
30+
931
self.addEventListener("activate",event => {
10-
event.waitUntil(caches.keys().then(versions => Promise.all(versions.map(cache => {
11-
if (cache.startsWith("Smart Text Editor") && cache !== Editor.version) return caches.delete(cache);
12-
}))));
13-
event.waitUntil(clients.claim());
14-
postMessageAllClients({ action: "service-worker-activated" });
32+
event.waitUntil(caches.keys().then(async keys => {
33+
const results = keys.map(async key => {
34+
if (key.startsWith("Smart Text Editor") && key !== STE.version){
35+
return caches.delete(key);
36+
}
37+
});
38+
await Promise.all(results);
39+
await self.clients.claim();
40+
return messageClients({ action: "service-worker-activated" });
41+
}));
1542
});
16-
self.addEventListener("fetch",event => {
43+
44+
self.addEventListener("fetch",async event => {
1745
if (event.request.method === "POST"){
18-
event.respondWith(Response.redirect("/?share-target=true",303));
19-
return event.waitUntil((async () => {
20-
Editor.share_files = Array.from(await event.request.formData()).map(file => file[1]);
46+
event.waitUntil((async () => {
47+
const formData = await event.request.formData();
48+
const files = formData.getAll("file");
49+
for (const file of files){
50+
STE.shareFiles.push(file as File);
51+
}
52+
event.respondWith(Response.redirect("./?share-target=true",303));
2153
})());
54+
return;
2255
}
23-
if (event.request.url === `${self.location.href.match("(.*\/).*")[1]}manifest.webmanifest`){
24-
return event.respondWith(caches.match(event.request).then(response => {
25-
return response || fetch("manifest.webmanifest").then(async request => {
26-
const manifest = await request.json();
27-
manifest.icons = manifest.icons.filter(icon => {
28-
if (!Editor.environment().macOS_device && icon.platform !== "macOS") return icon;
29-
if (Editor.environment().macOS_device && icon.platform === "macOS" || icon.purpose === "maskable") return icon;
56+
57+
if (event.request.url === `${(self.location.href.match("(.*\/).*") || "")[1]}manifest.webmanifest`){
58+
event.respondWith(caches.match(event.request).then(async response => {
59+
const result = response || fetch("./manifest.webmanifest").then(async response => {
60+
const manifest = await response.json();
61+
manifest.icons = manifest.icons.filter((icon: { platform: string; purpose: string; }) => {
62+
switch (true){
63+
case !STE.environment.macOSDevice && icon.platform !== "macOS":
64+
case STE.environment.macOSDevice && icon.platform === "macOS" || icon.purpose === "maskable": {
65+
return icon;
66+
}
67+
}
3068
});
31-
const response = new Response(new Blob([JSON.stringify(manifest,null," ")],{ type: "text/json" }));
32-
if (Editor.cache) caches.open(Editor.version).then(cache => cache.put(event.request,response));
69+
response = new Response(new Blob([JSON.stringify(manifest,null,2)],{ type: "text/json" }));
70+
if (STE.cache){
71+
const cache = await caches.open(STE.version);
72+
cache.put(event.request,response);
73+
}
3374
return response.clone();
3475
});
76+
return result;
3577
}));
3678
}
37-
event.respondWith(caches.match(event.request).then(response => {
38-
return response || fetch(event.request).then(async response => {
39-
if (Editor.cache) caches.open(Editor.version).then(cache => cache.put(event.request,response));
79+
80+
event.respondWith(caches.match(event.request).then(async response => {
81+
const result = response || fetch(event.request).then(async response => {
82+
if (STE.cache){
83+
const cache = await caches.open(STE.version);
84+
await cache.put(event.request,response);
85+
}
4086
return response.clone();
4187
});
88+
return result;
4289
}));
4390
});
44-
self.addEventListener("message",event => {
45-
if (event.data.action === "share-target"){
46-
clients.matchAll().then(clients => clients.filter(client => client.id === event.source.id).forEach(client => client.postMessage({ action: "share-target", files: Editor.share_files })));
47-
}
48-
if (event.data.action === "clear-site-caches"){
49-
caches.keys().then(versions => {
50-
Promise.all(versions.map(cache => caches.delete(cache)));
51-
postMessageAllClients({ action: "clear-site-caches-complete" });
52-
});
91+
92+
self.addEventListener("message",async event => {
93+
switch (event.data.action){
94+
case "share-target": {
95+
const client = event.source;
96+
client?.postMessage({ action: "share-target", files: STE.shareFiles });
97+
break;
98+
}
99+
case "clear-site-caches": {
100+
const keys = await caches.keys();
101+
const results = keys.map(key => {
102+
if (key.startsWith("Smart Text Editor")){
103+
return caches.delete(key);
104+
}
105+
});
106+
await Promise.all(results);
107+
await messageClients({ action: "clear-site-caches-complete" });
108+
break;
109+
}
53110
}
54111
});
55-
function postMessageAllClients(data){
56-
clients.matchAll().then(clients => clients.forEach(client => client.postMessage(data)));
112+
113+
async function messageClients(message: any, options: StructuredSerializeOptions = {}){
114+
const clients = await self.clients.matchAll();
115+
for (const client of clients){
116+
client.postMessage(message,options);
117+
}
57118
}

0 commit comments

Comments
 (0)