En este codelab, se muestra cómo implementar una experiencia de búsqueda resiliente con Workbox. La app de demostración que usa contiene un cuadro de búsqueda que llama a un extremo del servidor y redirecciona al usuario a una página HTML básica.
Medir
Antes de agregar optimizaciones, siempre se recomienda analizar el estado actual de la aplicación.
- Haz clic en Remix para editar para que el proyecto se pueda editar.
- Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa
En la pestaña nueva que se acaba de abrir, verifica cómo se comporta el sitio web cuando estás sin conexión:
- Presiona `Control + Mayúsculas + J` (o `Command + Option + J` en Mac) para abrir Herramientas para desarrolladores.
- Haga clic en la pestaña Red.
- Abre las Herramientas para desarrolladores de Chrome y selecciona el panel Red.
- En la lista desplegable Limitación, selecciona Sin conexión.
- En la app de demo, ingresa una búsqueda y, luego, haz clic en el botón Search.
Se muestra la página de error estándar del navegador:
Proporciona una respuesta de resguardo
El service worker contiene el código para agregar la página sin conexión a la lista de memoria caché previa, de modo que siempre se pueda almacenar en caché en el evento install
del service worker.
Por lo general, deberás indicarle a Workbox que agregue este archivo a la lista de almacenamiento previo en caché durante la compilación. Para ello, debes integrar la biblioteca a la herramienta de compilación que prefieras (p. ej., webpack o gulp).
Para mayor simplicidad, ya lo hicimos por ti. El siguiente código en public/sw.js
lo hace:
const FALLBACK_HTML_URL = '/index_offline.html';
…
workbox.precaching.precacheAndRoute([FALLBACK_HTML_URL]);
A continuación, agrega código para usar la página sin conexión como respuesta de resguardo:
- Para ver la fuente, presiona Ver fuente.
- Agrega el siguiente código al final de
public/sw.js
:
workbox.routing.setDefaultHandler(new workbox.strategies.NetworkOnly());
workbox.routing.setCatchHandler(({event}) => {
switch (event.request.destination) {
case 'document':
return caches.match(FALLBACK_HTML_URL);
break;
default:
return Response.error();
}
});
El código hace lo siguiente:
- Define una estrategia predeterminada del tipo Solo red que se aplicará a todas las solicitudes.
- Declara un controlador de errores global llamando a
workbox.routing.setCatchHandler()
para administrar las solicitudes con errores. Cuando las solicitudes son de documentos, se mostrará una página HTML de resguardo sin conexión.
Para probar esta funcionalidad, haz lo siguiente:
- Regresa a la otra pestaña que ejecuta la app.
- Vuelve a establecer la lista desplegable Regulación como En línea.
- Presiona el botón Atrás de Chrome para volver a la página de búsqueda.
- Asegúrate de que la casilla de verificación Inhabilitar caché en Herramientas para desarrolladores esté inhabilitada.
- Mantén presionado el botón Volver a cargar de Chrome y selecciona Vaciar la caché y realizar una recarga forzada para asegurarte de que tu service worker esté actualizado.
- Vuelve a establecer la lista desplegable Regulación en Sin conexión.
- Ingresa una búsqueda y vuelve a hacer clic en el botón Buscar.
Se muestra la página HTML de resguardo:
Cómo solicitar permisos de notificaciones
Para simplificar, la página sin conexión en views/index_offline.html
ya contiene el código para solicitar permisos de notificaciones en un bloque de secuencia de comandos en la parte inferior:
function requestNotificationPermission(event) {
event.preventDefault();
Notification.requestPermission().then(function (result) {
showOfflineText(result);
});
}
El código hace lo siguiente:
- Cuando el usuario hace clic en Suscribirse a notificaciones, se llama a la función
requestNotificationPermission()
, que llama aNotification.requestPermission()
, para mostrar el mensaje de permiso predeterminado del navegador. La promesa se resuelve con el permiso que eligió el usuario, que puede sergranted
,denied
odefault
. - Pasa el permiso resuelto a
showOfflineText()
para mostrarle el texto apropiado al usuario.
Conserva las búsquedas sin conexión y vuelve a intentarlo cuando vuelvas a estar en línea
A continuación, implementa la sincronización en segundo plano de Workbox para conservar las consultas sin conexión, de modo que se puedan volver a intentar cuando el navegador detecte que se devolvió la conectividad.
- Abre
public/sw.js
para editarlo. - Agrega el siguiente código al final del archivo:
const bgSyncPlugin = new workbox.backgroundSync.Plugin('offlineQueryQueue', {
maxRetentionTime: 60,
onSync: async ({queue}) => {
let entry;
while ((entry = await queue.shiftRequest())) {
try {
const response = await fetch(entry.request);
const cache = await caches.open('offline-search-responses');
const offlineUrl = `${entry.request.url}¬ification=true`;
cache.put(offlineUrl, response);
showNotification(offlineUrl);
} catch (error) {
await this.unshiftRequest(entry);
throw error;
}
}
},
});
El código hace lo siguiente:
workbox.backgroundSync.Plugin
contiene la lógica para agregar solicitudes fallidas a una cola de modo que se puedan reintentar más tarde. Estas solicitudes se conservarán en IndexedDB.maxRetentionTime
indica la cantidad de tiempo que se puede reintentar una solicitud. En este caso, elegimos 60 minutos (luego de los cuales se descartarán).onSync
es la parte más importante de este código. Se llamará a esta devolución de llamada cuando la conexión vuelva a estar disponible para que las solicitudes en cola se recuperen y luego se recuperen de la red.- La respuesta de red se agrega a la caché
offline-search-responses
y se agrega el parámetro de consulta¬ification=true
, de modo que se pueda obtener esta entrada de caché cuando un usuario haga clic en la notificación.
Para integrar la sincronización en segundo plano con tu servicio, define una estrategia NetworkOnly para las solicitudes a la URL de búsqueda (/search_action
) y pasa el bgSyncPlugin
definido anteriormente. Agrega el siguiente código al final de public/sw.js
:
const matchSearchUrl = ({url}) => {
const notificationParam = url.searchParams.get('notification');
return url.pathname === '/search_action' && !(notificationParam === 'true');
};
workbox.routing.registerRoute(
matchSearchUrl,
new workbox.strategies.NetworkOnly({
plugins: [bgSyncPlugin],
}),
);
Esto le indica a Workbox que siempre debe ir a la red y, cuando fallan las solicitudes, debe usar la lógica de sincronización en segundo plano.
A continuación, agrega el siguiente código al final de public/sw.js
para definir una estrategia de almacenamiento en caché para las solicitudes que provienen de notificaciones. Usa una estrategia CacheFirst para que se puedan publicar desde la caché.
const matchNotificationUrl = ({url}) => {
const notificationParam = url.searchParams.get('notification');
return (url.pathname === '/search_action' && (notificationParam === 'true'));
};
workbox.routing.registerRoute(matchNotificationUrl,
new workbox.strategies.CacheFirst({
cacheName: 'offline-search-responses',
})
);
Por último, agrega el código para mostrar notificaciones:
function showNotification(notificationUrl) {
if (Notification.permission) {
self.registration.showNotification('Your search is ready!', {
body: 'Click to see you search result',
icon: '/img/workbox.jpg',
data: {
url: notificationUrl
}
});
}
}
self.addEventListener('notificationclick', function(event) {
event.notification.close();
event.waitUntil(
clients.openWindow(event.notification.data.url)
);
});
Prueba la función
- Regresa a la otra pestaña que ejecuta la app.
- Vuelve a establecer la lista desplegable Regulación como En línea.
- Presiona el botón Atrás de Chrome para volver a la página de búsqueda.
- Mantén presionado el botón Volver a cargar de Chrome y selecciona Vaciar la caché y realizar una recarga forzada para asegurarte de que tu service worker esté actualizado.
- Vuelve a establecer la lista desplegable Regulación en Sin conexión.
- Ingresa una búsqueda y vuelve a hacer clic en el botón Buscar.
- Haz clic en Suscríbete a las notificaciones.
- Cuando Chrome te pregunte si quieres permitir que la app envíe notificaciones, haz lo siguiente: Haz clic en Permitir.
- Ingresa otra búsqueda y vuelve a hacer clic en el botón Buscar.
- Vuelve a establecer la lista desplegable Regulación en En línea.
Una vez que se restablezca la conexión, se mostrará una notificación:
Conclusión
Workbox proporciona muchas funciones integradas para que tus AWP sean más resilientes y atractivas. En este codelab, exploraste cómo implementar la API de Background Sync mediante la abstracción de Workbox para garantizar que no se pierdan las consultas de los usuarios sin conexión y que se puedan reintentar una vez que se restablezca la conexión. La demostración es una app de búsqueda simple, pero puedes usar una implementación similar para situaciones y casos de uso más complejos, incluidas apps de chat, publicación de mensajes en una red social, etcétera.