Skip to content

Commit 75fda4a

Browse files
committed
Improve service worker recovery and cache invalidation
1 parent ece2a47 commit 75fda4a

4 files changed

Lines changed: 53 additions & 2 deletions

File tree

app/layout.tsx

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,46 @@ export default function RootLayout({
114114
return (
115115
<html lang="en" className={`scroll-smooth ${generalSans.variable}`}>
116116
<head>
117+
<Script
118+
id="hydration-recovery"
119+
strategy="beforeInteractive"
120+
dangerouslySetInnerHTML={{
121+
__html: `
122+
(function () {
123+
var recoveryKey = 'lap_hydration_recovery_v1';
124+
window.setTimeout(async function () {
125+
if (document.documentElement.dataset.lapHydrated === 'true') {
126+
try { window.sessionStorage.removeItem(recoveryKey); } catch (_) {}
127+
return;
128+
}
129+
130+
try {
131+
if (window.sessionStorage.getItem(recoveryKey)) return;
132+
window.sessionStorage.setItem(recoveryKey, '1');
133+
134+
if ('serviceWorker' in navigator) {
135+
var registrations = await navigator.serviceWorker.getRegistrations();
136+
await Promise.all(registrations.map(function (registration) {
137+
return registration.unregister();
138+
}));
139+
}
140+
141+
if ('caches' in window) {
142+
var cacheNames = await window.caches.keys();
143+
await Promise.all(cacheNames.map(function (cacheName) {
144+
return window.caches.delete(cacheName);
145+
}));
146+
}
147+
148+
window.location.reload();
149+
} catch (_) {
150+
// Leave the rendered page in place if browser storage is unavailable.
151+
}
152+
}, 8000);
153+
})();
154+
`,
155+
}}
156+
/>
117157
{/* Google Analytics */}
118158
{GA_TRACKING_ID && (
119159
<>
@@ -148,8 +188,9 @@ export default function RootLayout({
148188
__html: `
149189
if ('serviceWorker' in navigator) {
150190
window.addEventListener('load', function() {
151-
navigator.serviceWorker.register('/sw.js').then(function(reg) {
191+
navigator.serviceWorker.register('/sw.js?v=3', { updateViaCache: 'none' }).then(function(reg) {
152192
console.log('SW registered:', reg.scope);
193+
reg.update().catch(function() {});
153194
}).catch(function(err) {
154195
console.warn('SW registration failed:', err);
155196
});

lib/public-auth-context.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,15 @@ export function PublicAuthProvider({ children }: { children: ReactNode }) {
303303
const [isDeviceBlocked, setIsDeviceBlocked] = useState(false);
304304
const [deviceBlockReason, setDeviceBlockReason] = useState("");
305305

306+
useEffect(() => {
307+
document.documentElement.dataset.lapHydrated = "true";
308+
try {
309+
window.sessionStorage.removeItem("lap_hydration_recovery_v1");
310+
} catch {
311+
// Storage can be unavailable in private browsing; hydration still succeeded.
312+
}
313+
}, []);
314+
306315
const refreshProfile = useCallback(async () => {
307316
const currentUser = auth.currentUser;
308317
if (!currentUser) {

netlify.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
for = "/sw.js"
2020
[headers.values]
2121
X-Robots-Tag = "noindex"
22+
Cache-Control = "no-cache, no-store, must-revalidate"
2223

2324
[[redirects]]
2425
from = "/&"

public/sw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const CACHE_NAME = 'lap-docs-cache-v2';
1+
const CACHE_NAME = 'lap-docs-cache-v3';
22
const ASSETS = [
33
'/icons/favicon-32x32.png',
44
'/icons/favicon-16x16.png',

0 commit comments

Comments
 (0)