Skip to content

Commit d84766d

Browse files
committed
Add streaming-service-worker
1 parent 953bd28 commit d84766d

File tree

35 files changed

+5237
-0
lines changed

35 files changed

+5237
-0
lines changed

streaming-service-worker/client/sw.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
const toCache = require('static-to-cache')();
2+
const version = require('static-version')();
3+
const revGet = require('static-rev-get');
4+
5+
const staticCacheName = `static-${version}`;
6+
7+
addEventListener('install', event => {
8+
skipWaiting();
9+
10+
event.waitUntil(async function () {
11+
const cache = await caches.open(staticCacheName);
12+
await cache.addAll(toCache);
13+
}());
14+
});
15+
16+
addEventListener('activate', event => {
17+
event.waitUntil(async function () {
18+
const keys = await caches.keys();
19+
await Promise.all(
20+
keys.map(key => {
21+
if (key !== staticCacheName) return caches.delete(key);
22+
})
23+
);
24+
}());
25+
});
26+
27+
class IdentityStream {
28+
constructor() {
29+
let readableController;
30+
let writableController;
31+
32+
this.readable = new ReadableStream({
33+
start(controller) {
34+
readableController = controller;
35+
},
36+
cancel(reason) {
37+
writableController.error(reason);
38+
}
39+
});
40+
41+
this.writable = new WritableStream({
42+
start(controller) {
43+
writableController = controller;
44+
},
45+
write(chunk) {
46+
readableController.enqueue(chunk);
47+
},
48+
close() {
49+
readableController.close();
50+
},
51+
abort(reason) {
52+
readableController.error(reason);
53+
}
54+
});
55+
}
56+
}
57+
58+
async function streamArticle(event, url) {
59+
const includeUrl = new URL(url);
60+
includeUrl.pathname += 'include';
61+
62+
const parts = [
63+
caches.match(revGet('/static/shell-start.html')),
64+
fetch(includeUrl).catch(() => caches.match(revGet('/static/offline-inc.html'))),
65+
caches.match(revGet('/static/shell-end.html'))
66+
];
67+
68+
const identity = new IdentityStream();
69+
70+
event.waitUntil(async function() {
71+
for (const responsePromise of parts) {
72+
const response = await responsePromise;
73+
await response.body.pipeTo(identity.writable, { preventClose: true });
74+
}
75+
identity.writable.getWriter().close();
76+
}());
77+
78+
return new Response(identity.readable, {
79+
headers: { 'Content-Type': 'text/html; charset=utf-8' }
80+
});
81+
}
82+
83+
addEventListener('fetch', event => {
84+
if (event.request.method !== 'GET') return;
85+
const url = new URL(event.request.url);
86+
87+
event.respondWith(async function () {
88+
if (url.origin === location.origin && /^\/\d{4}\/[\w-]+\/$/.test(url.pathname)) {
89+
return streamArticle(event, url);
90+
}
91+
92+
const cachedReponse = await caches.match(event.request);
93+
if (cachedReponse) return cachedReponse;
94+
95+
return await fetch(event.request);
96+
}());
97+
});

0 commit comments

Comments
 (0)