@rmdes/indiekit-frontend 1.0.0-beta.34 → 1.0.0-beta.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -76,24 +76,14 @@ async function clearOldCaches() {
76
76
  }
77
77
  }
78
78
 
79
- /**
80
- * Clear the pages cache so stale HTML (with old asset references) is not served
81
- */
82
- async function clearPagesCache() {
83
- try {
84
- await caches.delete(pagesCacheName);
85
- } catch (error) {
86
- console.error("Error clearing pages cache", error);
87
- }
88
- }
89
-
90
79
  /**
91
80
  * Notify all clients that the service worker has been updated
92
81
  */
93
82
  async function notifyClients() {
83
+ const version = assetCacheName.replace("assets-", "");
94
84
  const allClients = await clients.matchAll({ includeUncontrolled: true });
95
85
  for (const client of allClients) {
96
- client.postMessage({ command: "SW_UPDATED", version: "APP_VERSION" });
86
+ client.postMessage({ command: "SW_UPDATED", version });
97
87
  }
98
88
  }
99
89
 
@@ -130,7 +120,10 @@ self.addEventListener("activate", async (event) => {
130
120
  event.waitUntil(
131
121
  (async () => {
132
122
  await clearOldCaches();
133
- await clearPagesCache();
123
+ // Don't clear pages cache on activate — stale cached pages provide a
124
+ // valuable fallback when the network is slow (e.g. right after a deploy).
125
+ // The network-first fetch strategy naturally updates cached pages on
126
+ // every successful navigation, so stale entries are short-lived.
134
127
  await clients.claim();
135
128
  await notifyClients();
136
129
  })(),
@@ -158,44 +151,53 @@ self.addEventListener("fetch", (event) => {
158
151
  return;
159
152
  }
160
153
 
161
- // For HTML requests, try network with timeout, fall back to cache
154
+ // For HTML requests: network-first with conditional timeout
155
+ // - If a cached version exists: race network against timeout, serve cache on timeout
156
+ // - If no cached version: wait for network without timeout (avoid premature "Offline")
162
157
  if (
163
158
  request.mode === "navigate" ||
164
- request.headers.get("Accept").includes("text/html")
159
+ (request.headers.get("Accept") || "").includes("text/html")
165
160
  ) {
166
161
  event.respondWith(
167
162
  (async () => {
163
+ // Check cache and start network fetch in parallel
164
+ const cachedResponse = await caches.match(request);
165
+ const networkFetch = (async () => {
166
+ const preloadResponse = await Promise.resolve(event.preloadResponse);
167
+ return preloadResponse || (await fetch(request));
168
+ })();
169
+
168
170
  try {
169
- // Race network against a timeout for faster fallback on slow connections
170
- const responseFromPreloadOrFetch = await Promise.race([
171
- (async () => {
172
- const preloadResponse = await Promise.resolve(
173
- event.preloadResponse,
174
- );
175
- return preloadResponse || (await fetch(request));
176
- })(),
177
- new Promise((_, reject) =>
178
- setTimeout(() => reject(new Error("Network timeout")), timeout),
179
- ),
180
- ]);
171
+ // Only apply timeout when we have a cached fallback.
172
+ // Without a cache, it's better to wait for the network (loading spinner)
173
+ // than to show "Offline" after 5 seconds on a slow backend.
174
+ const responseFromNetwork = cachedResponse
175
+ ? await Promise.race([
176
+ networkFetch,
177
+ new Promise((_, reject) =>
178
+ setTimeout(
179
+ () => reject(new Error("Network timeout")),
180
+ timeout,
181
+ ),
182
+ ),
183
+ ])
184
+ : await networkFetch;
181
185
 
182
186
  // NETWORK succeeded — cache and serve
183
187
  try {
184
- const copy = responseFromPreloadOrFetch.clone();
188
+ const copy = responseFromNetwork.clone();
185
189
  const pagesCache = await caches.open(pagesCacheName);
186
190
  await pagesCache.put(request, copy);
187
191
  } catch (cacheError) {
188
192
  console.error("Failed to cache page:", cacheError);
189
193
  }
190
194
 
191
- return responseFromPreloadOrFetch;
195
+ return responseFromNetwork;
192
196
  } catch {
193
- // NETWORK failed or timed out — fall back to cache
194
- const responseFromCache = await caches.match(request);
195
- const offlineResponse = await caches.match("/offline");
197
+ // NETWORK failed or timed out — fall back to cache or offline
196
198
  return (
197
- responseFromCache ||
198
- offlineResponse ||
199
+ cachedResponse ||
200
+ (await caches.match("/offline")) ||
199
201
  new Response("Offline", {
200
202
  status: 503,
201
203
  statusText: "Service Unavailable",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-frontend",
3
- "version": "1.0.0-beta.34",
3
+ "version": "1.0.0-beta.36",
4
4
  "description": "Frontend components for Indiekit (fork with floating toolbar)",
5
5
  "keywords": [
6
6
  "express",