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 primer codelab de una serie complementaria del taller de apps web progresivas. Hay siete codelabs más en esta serie.

Qué aprenderás

  • Cómo escribir un Service Worker de forma manual
  • Cómo agregar un Service Worker a una aplicación web existente
  • Usa el Service Worker y la API de Cache Storage para que los recursos estén disponibles sin conexión

Lo que debe saber

  • Conocimientos básicos de HTML y JavaScript

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.

Este código base 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 existentes clave con los que trabajarás a lo largo de este codelab:

Archivos de claves

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

3. Prueba sin conexión

Antes de realizar cualquier cambio, probemos para demostrar que la app web no funciona sin conexión actualmente. Para ello, desconecta la computadora de Internet 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 Sin conexión.
  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 se comprobó que no se carga sin conexión, es hora de agregar algunas funciones en línea. Desmarca 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 ocurrirá en dos pasos: registrar el trabajador de servicio y almacenar en caché los recursos.

Cómo registrar 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 vacío del service worker service-worker.js una vez que se carga la página y solo si el sitio admite service workers.

Recursos de almacenamiento previo en caché

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 trabajador de servicio.

Luego, vuelve a desconectarte y actualiza el sitio. Deberías ver que se carga incluso sin conexión.

Explicación

Durante el evento de instalación del service worker, se abre una caché con nombre a través de 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 denomina almacenamiento previo en caché 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é y, si la encuentra, responde con el recurso almacenado en caché. Si no hay 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 Trabaja con Workbox.