Some checks failed
Build and Push Docker Images / docker (push) Failing after 44s
Implements comprehensive service worker solution with: - Dynamic versioning using git commit hash or timestamp - Automatic cache invalidation on new deployments - Hourly update checks and user notifications - Network-first caching strategy with 24-hour expiration - Build automation via prebuild script - Update notification UI component This prevents stale cached code from causing white screens by ensuring users always get the latest version after deployment. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
107 lines
3.1 KiB
TypeScript
107 lines
3.1 KiB
TypeScript
// Service Worker registration with automatic update detection for Next.js
|
|
// This ensures users always get the latest version after deployment
|
|
|
|
type Config = {
|
|
onUpdate?: (registration: ServiceWorkerRegistration) => void;
|
|
onSuccess?: (registration: ServiceWorkerRegistration) => void;
|
|
};
|
|
|
|
export function register(config?: Config) {
|
|
if (typeof window !== 'undefined' && 'serviceWorker' in navigator) {
|
|
// Wait for page load to avoid impacting initial page load performance
|
|
window.addEventListener('load', () => {
|
|
const swUrl = `/sw.js`;
|
|
|
|
registerValidSW(swUrl, config);
|
|
|
|
// Check for updates every hour
|
|
setInterval(() => {
|
|
checkForUpdates(swUrl);
|
|
}, 60 * 60 * 1000); // 1 hour
|
|
});
|
|
}
|
|
}
|
|
|
|
function registerValidSW(swUrl: string, config?: Config) {
|
|
navigator.serviceWorker
|
|
.register(swUrl)
|
|
.then((registration) => {
|
|
// Check for updates on initial registration
|
|
registration.update();
|
|
|
|
registration.onupdatefound = () => {
|
|
const installingWorker = registration.installing;
|
|
if (installingWorker == null) {
|
|
return;
|
|
}
|
|
|
|
installingWorker.onstatechange = () => {
|
|
if (installingWorker.state === 'installed') {
|
|
if (navigator.serviceWorker.controller) {
|
|
// New content is available; please refresh
|
|
console.log('New content available! Please refresh.');
|
|
|
|
// Execute onUpdate callback
|
|
if (config && config.onUpdate) {
|
|
config.onUpdate(registration);
|
|
}
|
|
} else {
|
|
// Content is cached for offline use
|
|
console.log('Content cached for offline use.');
|
|
|
|
// Execute onSuccess callback
|
|
if (config && config.onSuccess) {
|
|
config.onSuccess(registration);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
};
|
|
})
|
|
.catch((error) => {
|
|
console.error('Error during service worker registration:', error);
|
|
});
|
|
}
|
|
|
|
function checkForUpdates(swUrl: string) {
|
|
navigator.serviceWorker
|
|
.getRegistration(swUrl)
|
|
.then((registration) => {
|
|
if (registration) {
|
|
registration.update();
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
console.error('Error checking for service worker updates:', error);
|
|
});
|
|
}
|
|
|
|
export function unregister() {
|
|
if (typeof window !== 'undefined' && 'serviceWorker' in navigator) {
|
|
navigator.serviceWorker.ready
|
|
.then((registration) => {
|
|
registration.unregister();
|
|
})
|
|
.catch((error) => {
|
|
console.error(error.message);
|
|
});
|
|
}
|
|
}
|
|
|
|
// Force refresh when a new service worker is waiting
|
|
export function skipWaitingAndReload() {
|
|
if (typeof window !== 'undefined') {
|
|
navigator.serviceWorker.ready.then((registration) => {
|
|
if (registration.waiting) {
|
|
// Tell the waiting service worker to skip waiting and become active
|
|
registration.waiting.postMessage({ type: 'SKIP_WAITING' });
|
|
}
|
|
});
|
|
|
|
// Listen for the controller change and reload
|
|
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
|
window.location.reload();
|
|
});
|
|
}
|
|
}
|