App web progressive: lavorare con i service worker

1. Ti diamo il benvenuto

In questo lab, prenderai un'applicazione web esistente e aggiungerai un web worker per condividere lo stato tra due finestre aperte. Questo è l'ottavo di una serie di codelab complementari per il workshop sulle app web progressive. Il codelab precedente era Service Worker Includes. Questo è l'ultimo codelab della serie.

Obiettivi didattici

  • Aggiungere un worker condiviso tra più finestre aperte
  • Utilizzare Comlink per semplificare il lavoro con i lavoratori

Che cosa devi sapere

  • JavaScript

Che cosa ti serve

2. Configurazione

Inizia clonando o scaricando il codice iniziale necessario per completare questo codelab:

Se cloni il repository, assicurati di trovarti nel ramo pwa06--working-with-workers. Il file zip contiene anche il codice per questo ramo.

Questo codebase richiede Node.js 14 o versioni successive. Una volta disponibile il codice, esegui npm ci dalla riga di comando nella cartella del codice per installare tutte le dipendenze necessarie. Poi, esegui npm start per avviare il server di sviluppo per il codelab.

Il file README.md del codice sorgente fornisce una spiegazione per tutti i file distribuiti. Inoltre, i seguenti sono i file esistenti chiave con cui lavorerai durante questo codelab:

File delle chiavi

  • js/preview.js - File JavaScript della pagina di anteprima
  • js/main.js - File JavaScript dell'applicazione principale

3. Scrivi un lavoratore

Al momento, la funzionalità di anteprima della tua web app mostra solo i contenuti più recenti al caricamento. Idealmente, dovrebbe mostrare un'anteprima dal vivo mentre l'utente digita. Ciò richiede la compilazione di quantità potenzialmente grandi di dati e il loro trasferimento tra due finestre aperte diverse. Per questo motivo, non vogliamo che venga eseguita sul thread principale di nessuna delle finestre aperte. Utilizziamo invece un web worker condiviso.

Per iniziare, crea un file js/worker.js con il seguente codice:

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]);

Spiegazione

Questo codice configura una classe, chiamata Compiler, che consente di impostare i contenuti e di chiamare gli abbonamenti una volta compilati i contenuti. Poiché si tratta di un worker condiviso, deve essere utilizzata una sola istanza di questa classe, quindi viene creata una nuova istanza di Compiler. Poi, per rendere l'utilizzo di questa classe semplice dall'esterno del worker, viene utilizzato Comlink per esporre l'istanza del compilatore, consentendoci di utilizzare tutti i relativi metodi come se fossero dichiarati nel codice che la utilizza. Poiché si tratta di un worker condiviso anziché di un worker dedicato, deve essere esposto a tutte le connessioni.

4. Inviare contenuti al lavoratore

Ora che il worker è stato creato, dobbiamo inviargli i contenuti. Per farlo, aggiorna js/main.js in modo che:

  • Importa l'esportazione denominata wrap da comlink
  • Crea un nuovo Shared Worker di tipo modulo chiamato worker, imposta il tipo su module e puntalo utilizzando il pattern new URL (new URL('./worker.js', import.meta.url))
  • Crea una variabile compiler che wrap il worker.port
  • Nella funzione di aggiornamento dell'editor (editor.onUpdate), dopo aver salvato i contenuti nel database, attendi il completamento di compiler.set, passando i contenuti

Spiegazione

Il wrapping di un'esportazione di Comlink consente di utilizzare elementi come i metodi di classe esposti come se non fossero condivisi oltre il limite di un worker, con l'eccezione che ora tutto è asincrono. Poiché si tratta di un worker condiviso anziché di un worker dedicato, Comlink deve eseguire il wrapping della porta del worker anziché del worker stesso. Ora, ogni volta che viene apportato un aggiornamento all'editor, i contenuti vengono inviati al worker per essere elaborati.

5. Aggiornare la pagina di anteprima

Il passaggio finale consiste nell'estrarre i contenuti compilati dal worker condiviso e inserirli nell'anteprima. La configurazione per farlo è in gran parte la stessa, ma poiché le funzioni non possono passare tra i limiti dei worker, è necessario utilizzare un proxy per la funzione. Comlink, ancora una volta, è qui per aiutarti. Aggiorna js/preview.js per:

  • Importa le esportazioni denominate wrap e proxy da comlink
  • Crea e esegui il wrapping del worker condiviso come hai fatto in js/main.js
  • Chiama il metodo subscribe del compilatore con una funzione proxy che imposta la proprietà compiled dei dati in entrata sull'HTML interno dell'area di anteprima

Una volta fatto, apri l'anteprima, inizia a digitare nell'editor e divertiti a guardare il tuo markdown compilarsi e apparire in tempo reale nell'area di anteprima, il tutto senza bloccare il thread principale di nessuna delle pagine.

6. Complimenti!

Hai imparato a utilizzare un service worker condiviso per condividere lo stato tra più istanze PWA.