Apps web progresivas: Cómo trabajar con Workers

1. Te damos la bienvenida

En este lab, tomarás una aplicación web existente y agregarás un trabajador web para compartir el estado entre dos ventanas abiertas. Este es el octavo de una serie de codelabs complementarios para el taller de apps web progresivas. El codelab anterior fue Service Worker Includes. Este es el último codelab de la serie.

Qué aprenderás

  • Cómo agregar un trabajador compartido entre varias ventanas abiertas
  • Usa Comlink para facilitar el trabajo con los trabajadores

Lo que debe saber

  • 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 pwa06--working-with-workers. 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/preview.js: Archivo JavaScript de la página de vista previa
  • js/main.js: Archivo JavaScript principal de la aplicación

3. Escribe un Worker

Actualmente, la función de vista previa de tu app web solo muestra el contenido más reciente cuando se carga. Lo ideal sería que se mostrara una vista previa en vivo mientras el usuario escribe. Esto requiere compilar cantidades potencialmente grandes de datos y transportarlos entre dos ventanas abiertas diferentes. Por este motivo, no es algo que queramos hacer en el subproceso principal de ninguna de las ventanas abiertas. En su lugar, usemos un Web Worker compartido.

Para comenzar, crea un archivo js/worker.js con el siguiente código:

import { expose } from 'comlink';
import { marked } from 'marked';

class Compiler {
  state = {
    raw: '',
    compiled: '',
  };
  subscribers = [];

  async set(content) {
    this.state = {
      raw: content,
      compiled: marked(content),
    };

    await Promise.all(this.subscribers.map((s) => s(this.state)));
  }

  subscribe(cb) {
    this.subscribers.push(cb);
  }
}

const compiler = new Compiler();

onconnect = (e) => expose(compiler, e.ports[0]);

Explicación

Este código configura una clase, llamada Compiler, que permite establecer contenido y llamar a suscripciones una vez que se haya compilado ese contenido. Como es un trabajador compartido, solo debe usarse una instancia de esta clase, por lo que se crea una instancia nueva de Compiler. Luego, para que trabajar con esta clase se sienta fluido desde fuera del trabajador, se usa Comlink para exponer la instancia del compilador, lo que nos permite usar todos sus métodos como si se hubieran declarado en el código que lo usa. Debido a que se trata de un trabajador compartido en lugar de uno dedicado, debe exponerse a todas las conexiones.

4. Envía contenido al trabajador

Una vez creado el trabajador, ahora debemos enviarle contenido. Para ello, actualiza js/main.js para que haga lo siguiente:

  • Importa la exportación con nombre wrap desde comlink
  • Crea un nuevo Shared Worker con tipo de módulo llamado worker, establece su tipo en module y apunta a él con el patrón new URL (new URL('./worker.js', import.meta.url)).
  • Crea una variable compiler que wrap el worker.port
  • En la función de actualización del editor (editor.onUpdate), después de guardar el contenido en la base de datos, espera a que termine compiler.set y pasa el contenido.

Explicación

Encapsular una exportación de Comlink permite que se usen elementos como los métodos de clase expuestos como si no se compartieran a través de un límite de trabajador, con la excepción de que ahora todo es asíncrono. Debido a que se trata de un trabajador compartido en lugar de uno dedicado, Comlink necesita encapsular el puerto del trabajador en lugar del trabajador en sí. Ahora, cada vez que se realice una actualización en el editor, el contenido se enviará al trabajador para que lo procese.

5. Actualiza la página de vista previa

El último paso es obtener el contenido compilado del trabajador compartido en la vista previa. La configuración para hacerlo es prácticamente la misma, pero, como las funciones no pueden pasar el límite del trabajador, se debe usar un proxy para la función. Comlink, una vez más, está aquí para ayudarte. Actualiza js/preview.js para hacer lo siguiente:

  • Importa las exportaciones con nombre wrap y proxy desde comlink.
  • Crea y encapsula el trabajador compartido como lo hiciste en js/main.js
  • Llama al método subscribe del compilador con una función de proxy que establece la propiedad compiled de los datos entrantes en el HTML interno del área de vista previa.

Una vez que termines, abre la vista previa, comienza a escribir en el editor y diviértete viendo cómo tu Markdown se compila automáticamente y aparece en tiempo real en el área de vista previa, todo sin bloquear el subproceso principal de ninguna de las páginas.

6. ¡Felicitaciones!

Aprendiste a usar un trabajador compartido para compartir el estado entre varias instancias de la PWA.