Skip to content

Commit 261a601

Browse files
clairernovotnyjeromelaban
authored andcommitted
fix(service-worker): Enhance error handling and caching logic
1 parent c4964ca commit 261a601

File tree

1 file changed

+90
-36
lines changed

1 file changed

+90
-36
lines changed

src/Uno.Wasm.Bootstrap/Embedded/service-worker.js

Lines changed: 90 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { config as unoConfig } from "$(REMOTE_WEBAPP_PATH)$(REMOTE_BASE_PATH)/uno-config.js";
22

3-
43
if (unoConfig.environmentVariables["UNO_BOOTSTRAP_DEBUGGER_ENABLED"] !== "True") {
54
console.debug("[ServiceWorker] Initializing");
65
let uno_enable_tracing = unoConfig.uno_enable_tracing;
@@ -15,65 +14,120 @@ if (unoConfig.environmentVariables["UNO_BOOTSTRAP_DEBUGGER_ENABLED"] !== "True")
1514
// worker to fail installing.
1615
for (var i = 0; i < unoConfig.offline_files.length; i++) {
1716
try {
17+
const currentFile = unoConfig.offline_files[i];
1818
if (uno_enable_tracing) {
19-
console.debug(`[ServiceWorker] cache ${key}`);
19+
console.debug(`[ServiceWorker] caching ${currentFile}`);
2020
}
2121

22-
await cache.add(unoConfig.offline_files[i]);
22+
await cache.add(currentFile);
2323
}
2424
catch (e) {
25-
console.debug(`[ServiceWorker] Failed to fetch ${unoConfig.offline_files[i]}`);
25+
console.debug(`[ServiceWorker] Failed to fetch ${unoConfig.offline_files[i]}: ${e.message}`);
2626
}
2727
}
2828

2929
// Add the runtime's own files to the cache. We cannot use the
3030
// existing cached content from the runtime as the keys contain a
3131
// hash we cannot reliably compute.
32-
var c = await fetch("$(REMOTE_WEBAPP_PATH)_framework/blazor.boot.json");
33-
const monoConfigResources = (await c.json()).resources;
32+
try {
33+
var c = await fetch("$(REMOTE_WEBAPP_PATH)_framework/blazor.boot.json");
34+
// Response validation to catch HTTP errors early
35+
// This prevents trying to parse invalid JSON from error responses
36+
if (!c.ok) {
37+
throw new Error(`Failed to fetch blazor.boot.json: ${c.status} ${c.statusText}`);
38+
}
3439

35-
var entries = {
36-
...(monoConfigResources.coreAssembly || {})
37-
, ...(monoConfigResources.assembly || {})
38-
, ...(monoConfigResources.lazyAssembly || {})
39-
, ...(monoConfigResources.jsModuleWorker || {})
40-
, ...(monoConfigResources.jsModuleGlobalization || {})
41-
, ...(monoConfigResources.jsModuleNative || {})
42-
, ...(monoConfigResources.jsModuleRuntime || {})
43-
, ...(monoConfigResources.wasmNative || {})
44-
, ...(monoConfigResources.icu || {})
45-
, ...(monoConfigResources.coreAssembly || {})
46-
};
40+
const bootJson = await c.json();
41+
const monoConfigResources = bootJson.resources || {};
4742

48-
for (var key in entries) {
49-
var uri = `$(REMOTE_WEBAPP_PATH)_framework/${key}`;
43+
var entries = {
44+
...(monoConfigResources.coreAssembly || {}),
45+
...(monoConfigResources.assembly || {}),
46+
...(monoConfigResources.lazyAssembly || {}),
47+
...(monoConfigResources.jsModuleWorker || {}),
48+
...(monoConfigResources.jsModuleGlobalization || {}),
49+
...(monoConfigResources.jsModuleNative || {}),
50+
...(monoConfigResources.jsModuleRuntime || {}),
51+
...(monoConfigResources.wasmNative || {}),
52+
...(monoConfigResources.icu || {})
53+
};
5054

51-
if (uno_enable_tracing) {
52-
console.debug(`[ServiceWorker] cache ${uri}`);
53-
}
55+
for (var key in entries) {
56+
var uri = `$(REMOTE_WEBAPP_PATH)_framework/${key}`;
57+
58+
try {
59+
if (uno_enable_tracing) {
60+
console.debug(`[ServiceWorker] cache ${uri}`);
61+
}
5462

55-
await cache.add(uri);
63+
await cache.add(uri);
64+
} catch (e) {
65+
console.error(`[ServiceWorker] Failed to cache ${uri}:`, e.message);
66+
}
67+
}
68+
} catch (e) {
69+
// Centralized error handling for the entire boot.json processing
70+
console.error('[ServiceWorker] Error processing blazor.boot.json:', e.message);
5671
}
5772
})
5873
);
5974
});
6075

76+
// Cache cleanup logic to prevent storage bloat
77+
// This removes any old caches that might have been created by previous
78+
// versions of the service worker, helping prevent storage quota issues
6179
self.addEventListener('activate', event => {
62-
event.waitUntil(self.clients.claim());
80+
event.waitUntil(
81+
caches.keys().then(function (cacheNames) {
82+
return Promise.all(
83+
cacheNames.filter(function (cacheName) {
84+
return cacheName !== '$(CACHE_KEY)';
85+
}).map(function (cacheName) {
86+
console.debug('[ServiceWorker] Deleting old cache:', cacheName);
87+
return caches.delete(cacheName);
88+
})
89+
);
90+
}).then(function () {
91+
return self.clients.claim();
92+
})
93+
);
6394
});
6495

6596
self.addEventListener('fetch', event => {
66-
event.respondWith(async function () {
67-
try {
68-
// Network first mode to get fresh content every time, then fallback to
69-
// cache content if needed.
70-
return await fetch(event.request);
71-
} catch (err) {
72-
return caches.match(event.request).then(response => {
73-
return response || fetch(event.request);
74-
});
75-
}
76-
}());
97+
event.respondWith(
98+
(async function () {
99+
// FIXED: Critical fix for "already used" Request objects #956
100+
// Request objects can only be used once in a fetch operation
101+
// Cloning the request allows for reuse in fallback scenarios
102+
const requestClone = event.request.clone();
103+
104+
try {
105+
// Network first mode to get fresh content every time, then fallback to
106+
// cache content if needed.
107+
return await fetch(requestClone);
108+
} catch (err) {
109+
// Logging to track network failures
110+
console.debug(`[ServiceWorker] Network fetch failed, falling back to cache for: ${requestClone.url}`);
111+
112+
const cachedResponse = await caches.match(event.request);
113+
if (cachedResponse) {
114+
return cachedResponse;
115+
}
116+
117+
// Graceful error handling with a proper HTTP response
118+
// Rather than letting the fetch fail with a generic error,
119+
// we return a controlled 503 Service Unavailable response
120+
console.error(`[ServiceWorker] Resource not available in cache or network: ${requestClone.url}`);
121+
return new Response('Network error occurred, and resource was not found in cache.', {
122+
status: 503,
123+
statusText: 'Service Unavailable',
124+
headers: new Headers({
125+
'Content-Type': 'text/plain'
126+
})
127+
});
128+
}
129+
})()
130+
);
77131
});
78132
}
79133
else {

0 commit comments

Comments
 (0)