Actualización PWA Manual (v1.0.89)

Cambios Realizados
Service Worker (public/service-worker.js)
 Removido skipWaiting() automático en install
 Removido claim() automático en activate
 Solo se activa cuando recibe mensaje SKIP_WAITING del usuario
App.jsx
 Modal se muestra cuando hay actualización
 Nueva versión se instala en segundo plano
⏸️ Espera confirmación del usuario
 Solo actualiza cuando el usuario presiona el botón
 Protección contra recargas múltiples (refreshing flag)
Flujo Actualizado
Deploy de nueva versión (ej: v1.0.89)
Usuario abre la app con versión antigua (v1.0.88)
Service Worker detecta nueva versión
Descarga en segundo plano la nueva versión
Modal aparece → "¡Nueva Actualización!"
⏸️ La app sigue funcionando normalmente
👆 Usuario presiona "🚀 ACTUALIZAR AHORA"
Service Worker se activa (skipWaiting)
Página se recarga automáticamente
 Nueva versión activa
Ventajas
 Usuario tiene control total
 No interrumpe trabajo en curso
 Puede terminar inspección antes de actualizar
 Modal bloqueante asegura que eventualmente actualice
 Actualización instantánea al presionar botón
Ahora el usuario DEBE presionar el botón para actualizar! 🎯
This commit is contained in:
2025-11-30 23:30:57 -03:00
parent 14a64778b8
commit b2398efead
3 changed files with 19 additions and 9 deletions

View File

@@ -1,7 +1,7 @@
{ {
"name": "checklist-frontend", "name": "checklist-frontend",
"private": true, "private": true,
"version": "1.0.88", "version": "1.0.89",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -1,6 +1,6 @@
// Service Worker para PWA con detección de actualizaciones // Service Worker para PWA con detección de actualizaciones
// IMPORTANTE: Actualizar esta versión cada vez que se despliegue una nueva versión // IMPORTANTE: Actualizar esta versión cada vez que se despliegue una nueva versión
const CACHE_NAME = 'ayutec-v1.0.88'; const CACHE_NAME = 'ayutec-v1.0.89';
const urlsToCache = [ const urlsToCache = [
'/', '/',
'/index.html' '/index.html'
@@ -15,7 +15,7 @@ self.addEventListener('install', (event) => {
console.log('Service Worker: Caching files'); console.log('Service Worker: Caching files');
return cache.addAll(urlsToCache); return cache.addAll(urlsToCache);
}) })
.then(() => self.skipWaiting()) // Forzar activación inmediata // NO hacer skipWaiting automáticamente - esperar a que el usuario lo active
); );
}); });
@@ -32,7 +32,8 @@ self.addEventListener('activate', (event) => {
} }
}) })
); );
}).then(() => self.clients.claim()) // Tomar control de todas las páginas })
// NO hacer claim automáticamente - solo cuando el usuario actualice manualmente
); );
}); });

View File

@@ -21,6 +21,7 @@ function App() {
// Verificar si hay actualización esperando // Verificar si hay actualización esperando
if (registration.waiting) { if (registration.waiting) {
console.log('⚠️ Hay una actualización esperando');
setWaitingWorker(registration.waiting); setWaitingWorker(registration.waiting);
setUpdateAvailable(true); setUpdateAvailable(true);
} }
@@ -32,8 +33,8 @@ function App() {
newWorker.addEventListener('statechange', () => { newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) { if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
// Hay nueva versión disponible // Hay nueva versión disponible - MOSTRAR MODAL, NO ACTIVAR AUTOMÁTICAMENTE
console.log('✨ Nueva versión lista!'); console.log('✨ Nueva versión instalada - esperando confirmación del usuario');
setWaitingWorker(newWorker); setWaitingWorker(newWorker);
setUpdateAvailable(true); setUpdateAvailable(true);
} }
@@ -45,17 +46,25 @@ function App() {
}); });
// Escuchar cambios de controlador (cuando se activa nueva versión) // Escuchar cambios de controlador (cuando se activa nueva versión)
// SOLO se dispara DESPUÉS de que el usuario presione el botón
let refreshing = false;
navigator.serviceWorker.addEventListener('controllerchange', () => { navigator.serviceWorker.addEventListener('controllerchange', () => {
console.log('🔄 Controlador cambiado, recargando página...'); if (!refreshing) {
window.location.reload(); refreshing = true;
console.log('🔄 Controlador cambiado, recargando página...');
window.location.reload();
}
}); });
} }
}, []); }, []);
// Función para actualizar la app // Función para actualizar la app - SOLO cuando el usuario presiona el botón
const handleUpdate = () => { const handleUpdate = () => {
if (waitingWorker) { if (waitingWorker) {
console.log('👆 Usuario confirmó actualización - activando nueva versión...');
// Enviar mensaje al service worker para que se active
waitingWorker.postMessage({ type: 'SKIP_WAITING' }); waitingWorker.postMessage({ type: 'SKIP_WAITING' });
// El controllerchange listener manejará la recarga
} }
}; };