Apps web progresivas: Cómo trabajar sin conexión

1. Te damos la bienvenida

En este lab, tomarás una aplicación web existente y la harás funcionar sin conexión. Este es el primero de una serie de codelabs complementarios para el taller de Progressive Web App. Hay siete codelabs más en esta serie.

Qué aprenderás

  • Escribir un service worker de forma manual
  • Agregar un service worker a una aplicación web existente
  • Usar el service worker y la API de Cache Storage para que los recursos estén disponibles sin conexión

Lo que debe saber

  • HTML y JavaScript básicos

Lo que necesitarás

2. Prepárate

Para comenzar, clona o descarga el código de partida necesario para completar este codelab:

Si clonas el repositorio, asegúrate de estar en la rama starter. El archivo ZIP también contiene el código de esa rama.

Esta base de código requiere Node.js 14 o una versión posterior. Una vez que tengas el código disponible, ejecuta npm ci desde la línea de comandos en la carpeta del código para instalar todas las dependencias que necesitarás. Luego, ejecuta npm start para iniciar el servidor de desarrollo del codelab.

El archivo README.md del código fuente proporciona una explicación de todos los archivos distribuidos. Además, los siguientes son los archivos clave existentes con los que trabajarás durante este codelab:

Archivos clave

  • js/main.js: Archivo JavaScript principal de la aplicación
  • service-worker.js - Archivo de service worker de la aplicación

3. Prueba sin conexión

Antes de realizar cualquier cambio, hagamos una prueba para demostrar que la app web no funciona sin conexión en este momento. Para ello, desconecta nuestra computadora y vuelve a cargar la app web o, si usas Chrome, haz lo siguiente:

  1. Abre las Herramientas para desarrolladores de Chrome.
  2. Cambia a la pestaña Application.
  3. Cambia a la sección Service Workers.
  4. Marca la casilla de verificación Offline.
  5. Actualiza la página sin cerrar las Herramientas para desarrolladores de Chrome.

Pestaña Application de las Herramientas para desarrolladores de Chrome abierta en Service Workers con la casilla de verificación Offline marcada

Una vez que se probó el sitio y no se pudo cargar sin conexión, es hora de agregar algunas funciones en línea. Anula la selección de la casilla de verificación sin conexión y continúa con el siguiente paso.

4. Usa otras plataformas

Es hora de agregar un service worker básico. Esto sucederá en dos pasos: registrar el service worker y almacenar recursos en caché.

Registra un service worker

Ya hay un archivo de service worker vacío, por lo que, para asegurarnos de que se muestren los cambios, lo registraremos en nuestra aplicación. Para ello, agrega el siguiente código en la parte superior de js/main.js:

// Register the service worker
if ('serviceWorker' in navigator) {
  // Wait for the 'load' event to not block other work
  window.addEventListener('load', async () => {
    // Try to register the service worker.
    try {
      // Capture the registration for later use, if needed
      let reg;

      // Use ES Module version of our Service Worker in development
      if (import.meta.env?.DEV) {
        reg = await navigator.serviceWorker.register('/service-worker.js', {
          type: 'module',
        });
      } else {
        // In production, use the normal service worker registration
        reg = await navigator.serviceWorker.register('/service-worker.js');
      }

      console.log('Service worker registered! 😎', reg);
    } catch (err) {
      console.log('😥 Service worker registration failed: ', err);
    }
  });
}

Explicación

Este código registra el archivo de service worker service-worker.js vacío una vez que se carga la página y solo si el sitio admite service workers.

Recursos de precaché

Para que la app web funcione sin conexión, el navegador debe poder responder a las solicitudes de red y elegir dónde enrutarlas. Para ello, agrega lo siguiente a service-worker.js

// Choose a cache name
const cacheName = 'cache-v1';
// List the files to precache
const precacheResources = ['/', '/index.html', '/css/style.css', '/js/main.js', '/js/app/editor.js', '/js/lib/actions.js'];

// When the service worker is installing, open the cache and add the precache resources to it
self.addEventListener('install', (event) => {
  console.log('Service worker install event!');
  event.waitUntil(caches.open(cacheName).then((cache) => cache.addAll(precacheResources)));
});

self.addEventListener('activate', (event) => {
  console.log('Service worker activate event!');
});

// When there's an incoming fetch request, try and respond with a precached resource, otherwise fall back to the network
self.addEventListener('fetch', (event) => {
  console.log('Fetch intercepted for:', event.request.url);
  event.respondWith(
    caches.match(event.request).then((cachedResponse) => {
      if (cachedResponse) {
        return cachedResponse;
      }
      return fetch(event.request);
    }),
  );
});

Ahora, regresa al navegador, cierra la pestaña de vista previa y vuelve a abrirla. Deberías ver console.logs correspondientes a los diferentes eventos en el service worker.

A continuación, vuelve a desconectarte y actualiza el sitio. Deberías ver que se carga incluso si no tienes conexión.

Explicación

Durante el evento de instalación del service worker, se abre una caché con nombre mediante la API de Cache Storage. Luego, los archivos y las rutas especificados en precacheResources se cargan en la caché con el método cache.addAll. Esto se llama precaché porque almacena en caché de forma preventiva el conjunto de archivos durante el tiempo de instalación, en lugar de almacenarlos en caché cuando se necesitan o solicitan.

Una vez que el service worker controla el sitio, los recursos solicitados pasan por el service worker como un proxy. Cada solicitud activa un evento de recuperación que, en este service worker, busca una coincidencia en la caché. Si hay una coincidencia, responde con el recurso almacenado en caché. Si no hay una coincidencia, el recurso se solicita de forma normal.

El almacenamiento en caché de recursos permite que la app funcione sin conexión, ya que evita las solicitudes de red. Ahora, la app puede responder con un código de estado 200 cuando no hay conexión.

5. ¡Felicitaciones!

Aprendiste a desconectar tu app web con service workers y la API de Cache Storage.

El siguiente codelab de la serie es Cómo trabajar con Workbox.