Proto-to-Prod
This commit is contained in:
parent
82a8a6a21a
commit
5cabc31d37
63 changed files with 3783 additions and 602 deletions
|
|
@ -14,7 +14,7 @@
|
|||
// /audio /img → stale-while-revalidate from ASSET_CACHE
|
||||
// everything → cache-first from SHELL_CACHE
|
||||
// - Messages:
|
||||
// { type: 'precache-stops', urls: string[] }
|
||||
// { type: 'precache-artists', urls: string[] }
|
||||
// Bulk-cache a list of URLs into ASSET_CACHE, posting progress back to
|
||||
// the sender via { type: 'precache-progress', done, total } and a final
|
||||
// { type: 'precache-done' } when finished.
|
||||
|
|
@ -72,7 +72,6 @@ sw.addEventListener('fetch', (event) => {
|
|||
|
||||
event.respondWith(
|
||||
(async () => {
|
||||
// Navigation: prefer cached shell; fall back to network.
|
||||
if (request.mode === 'navigate') {
|
||||
const shell = await caches.open(SHELL_CACHE);
|
||||
const cached = (await shell.match('/')) || (await shell.match('/index.html'));
|
||||
|
|
@ -89,7 +88,6 @@ sw.addEventListener('fetch', (event) => {
|
|||
const cached = await cache.match(request);
|
||||
if (cached) {
|
||||
if (isContent) {
|
||||
// Stale-while-revalidate: return cached, refresh in background.
|
||||
event.waitUntil(refresh(cache, request));
|
||||
}
|
||||
return cached;
|
||||
|
|
@ -119,40 +117,79 @@ async function refresh(cache: Cache, request: Request) {
|
|||
|
||||
sw.addEventListener('message', (event) => {
|
||||
const data = event.data;
|
||||
if (data?.type !== 'precache-stops' || !Array.isArray(data.urls)) return;
|
||||
if (data?.type !== 'precache-artists' || !Array.isArray(data.urls)) return;
|
||||
|
||||
const urls: string[] = data.urls;
|
||||
const source = event.source;
|
||||
event.waitUntil(precacheStops(urls, source));
|
||||
event.waitUntil(precacheArtists(urls, source));
|
||||
});
|
||||
|
||||
async function precacheStops(urls: string[], source: Client | ServiceWorker | MessagePort | null) {
|
||||
async function precacheArtists(urls: string[], source: Client | ServiceWorker | MessagePort | null) {
|
||||
const cache = await caches.open(ASSET_CACHE);
|
||||
let done = 0;
|
||||
const total = urls.length;
|
||||
for (const url of urls) {
|
||||
try {
|
||||
const cached = await cache.match(url);
|
||||
if (!cached) {
|
||||
const res = await fetch(url, { credentials: 'same-origin' });
|
||||
if (res.ok && res.type === 'basic') await cache.put(url, res);
|
||||
}
|
||||
} catch {
|
||||
// Network error — skip and continue. UI shows the count.
|
||||
}
|
||||
done++;
|
||||
let done = 0;
|
||||
let failed = 0;
|
||||
|
||||
const queue = urls.slice();
|
||||
const CONCURRENCY = 3;
|
||||
const MAX_ATTEMPTS = 3;
|
||||
const BACKOFF_MS = 800;
|
||||
|
||||
function postProgress() {
|
||||
try {
|
||||
(source as Client | null)?.postMessage?.({
|
||||
type: 'precache-progress',
|
||||
done,
|
||||
total
|
||||
total,
|
||||
failed
|
||||
});
|
||||
} catch {
|
||||
// Sender went away.
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function fetchWithRetry(url: string): Promise<boolean> {
|
||||
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
||||
try {
|
||||
const res = await fetch(url, { credentials: 'same-origin', cache: 'no-store' });
|
||||
if (res.ok && res.type === 'basic') {
|
||||
await cache.put(url, res);
|
||||
return true;
|
||||
}
|
||||
if (res.status >= 400 && res.status < 500) return false; // permanent
|
||||
} catch {}
|
||||
if (attempt < MAX_ATTEMPTS) {
|
||||
await new Promise((r) => setTimeout(r, BACKOFF_MS * attempt));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function worker() {
|
||||
while (queue.length > 0) {
|
||||
const url = queue.shift();
|
||||
if (!url) break;
|
||||
try {
|
||||
const cached = await cache.match(url);
|
||||
if (!cached) {
|
||||
const ok = await fetchWithRetry(url);
|
||||
if (!ok) failed++;
|
||||
}
|
||||
} catch {
|
||||
failed++;
|
||||
}
|
||||
done++;
|
||||
postProgress();
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(Array.from({ length: CONCURRENCY }, worker));
|
||||
|
||||
try {
|
||||
(source as Client | null)?.postMessage?.({ type: 'precache-done', done, total });
|
||||
(source as Client | null)?.postMessage?.({
|
||||
type: 'precache-done',
|
||||
done,
|
||||
total,
|
||||
failed
|
||||
});
|
||||
} catch {
|
||||
// Sender went away.
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue