From 6875e8762ef3f99c9a2c251f5f8966a5efd15ee0 Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Sat, 2 May 2026 15:55:12 +0200 Subject: [PATCH] fix(offline): gate SW precache on controller, not just registration `navigator.serviceWorker.ready` resolves only when a SW is registered and active. In `vite dev` no SW exists, so awaiting `ready` hangs the sync forever. Gate on `navigator.serviceWorker.controller` first to short-circuit cleanly when nothing controls the page. Bump 1.57.7 -> 1.57.8. --- package.json | 2 +- src/lib/offline/sync.ts | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 693649f9..ee9e13d5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homepage", - "version": "1.57.7", + "version": "1.57.8", "private": true, "type": "module", "scripts": { diff --git a/src/lib/offline/sync.ts b/src/lib/offline/sync.ts index 3f39a924..1830b9bd 100644 --- a/src/lib/offline/sync.ts +++ b/src/lib/offline/sync.ts @@ -129,8 +129,10 @@ export async function downloadAllRecipes( } async function precacheMainPages(_fetchFn: typeof fetch): Promise { - // Only attempt if service worker is available - if (!('serviceWorker' in navigator)) return; + // Only attempt if service worker is available and controlling the page. + // `serviceWorker.ready` would hang forever in environments where no SW is + // registered (e.g. `vite dev`), so gate on `controller` first. + if (!('serviceWorker' in navigator) || !navigator.serviceWorker.controller) return; const registration = await navigator.serviceWorker.ready; if (!registration.active) return; @@ -186,8 +188,10 @@ async function precacheMainPages(_fetchFn: typeof fetch): Promise { } async function precacheRecipeData(recipes: BriefRecipeType[]): Promise { - // Only attempt if service worker is available - if (!('serviceWorker' in navigator)) return; + // Only attempt if service worker is available and controlling the page. + // `serviceWorker.ready` would hang forever in environments where no SW is + // registered (e.g. `vite dev`), so gate on `controller` first. + if (!('serviceWorker' in navigator) || !navigator.serviceWorker.controller) return; const registration = await navigator.serviceWorker.ready; if (!registration.active) return; @@ -264,8 +268,10 @@ async function precacheThumbnails( recipes: BriefRecipeType[], onProgress?: ProgressCallback ): Promise { - // Only attempt if service worker is available - if (!('serviceWorker' in navigator)) return; + // Only attempt if service worker is available and controlling the page. + // `serviceWorker.ready` would hang forever in environments where no SW is + // registered (e.g. `vite dev`), so gate on `controller` first. + if (!('serviceWorker' in navigator) || !navigator.serviceWorker.controller) return; const registration = await navigator.serviceWorker.ready; if (!registration.active) return;