プログレッシブ ウェブアプリ: Worker の使用

1. ようこそ

このラボでは、既存のウェブ アプリケーションにウェブ ワーカーを追加して、2 つの開いているウィンドウ間で状態を共有します。これは、プログレッシブ ウェブアプリ ワークショップのコンパニオン Codelab シリーズの 8 番目です。前の Codelab は Service Worker の組み込みでした。これは、このシリーズの最後の Codelab です。

学習内容

  • 開いている複数のウィンドウ間に共有ワーカーを追加する
  • Comlink を使用してワーカーの操作を簡単にする

必要な予備知識

  • JavaScript

必要なもの

2. 準備

まず、この Codelab を完了するために必要なスターター コードをクローンするかダウンロードします。

リポジトリのクローンを作成する場合は、pwa06--working-with-workers ブランチにいることを確認してください。zip ファイルには、そのブランチのコードも含まれています。

このコードベースには Node.js 14 以降が必要です。コードが用意できたら、コードのフォルダのコマンドラインから npm ci を実行して、必要なすべての依存関係をインストールします。次に、npm start を実行して、Codelab の開発用サーバーを起動します。

ソースコードの README.md ファイルには、すべての配布ファイルの説明が記載されています。また、この Codelab 全体を通して使用する主な既存のファイルは次のとおりです。

キーファイル

  • js/preview.js - プレビュー ページの JavaScript ファイル
  • js/main.js - メイン アプリケーションの JavaScript ファイル

3. ワーカーを作成する

現在、ウェブアプリのプレビュー機能では、読み込み時に最新のコンテンツのみが表示されます。理想的には、ユーザーが入力しているときにライブ プレビューが表示されるようにします。これには、大量のデータをコンパイルして、2 つの異なる開いているウィンドウ間で転送する必要があります。そのため、開いているウィンドウのメインスレッドで実行することはおすすめしません。代わりに、共有ウェブ ワーカーを使用しましょう。

まず、次のコードを含む js/worker.js ファイルを作成します。

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

説明

このコードは、コンテンツを設定できる Compiler というクラスを設定し、コンテンツがコンパイルされたらサブスクリプションを呼び出せるようにします。共有ワーカーであるため、このクラスのインスタンスは 1 つだけ使用する必要があります。そのため、Compiler の新しいインスタンスがインスタンス化されます。次に、このクラスをワーカーの外部からシームレスに操作できるように、Comlink を使用してコンパイラ インスタンスを公開します。これにより、このインスタンスのすべてのメソッドを、それを使用するコードで宣言されているかのように使用できます。これは専用ワーカーではなく共有ワーカーであるため、すべての接続に公開する必要があります。

4. ワーカーにコンテンツを送信する

ワーカーを作成したら、コンテンツをワーカーに送信する必要があります。そのため、js/main.js を更新して次の処理を行います。

  • comlink から名前付きエクスポート wrap をインポートする
  • worker という名前の新しいモジュール型の Shared Worker を作成し、その型を module に設定して、new URL パターン(new URL('./worker.js', import.meta.url))を使用して参照します。
  • worker.portwrap する compiler 変数を作成します。
  • エディタの更新関数(editor.onUpdate)で、コンテンツをデータベースに保存した後、コンテンツを渡して compiler.set が完了するまで待機します。

説明

Comlink エクスポートをラップすると、公開されたクラスメソッドがワーカー境界を越えて共有されていないかのように使用できます。ただし、すべてが非同期になるという例外があります。これは専用ワーカーではなく共有ワーカーであるため、Comlink はワーカー自体ではなくワーカーのポートをラップする必要があります。これで、エディタが更新されるたびに、コンテンツがワーカーに送信されて処理されるようになります。

5. プレビュー ページを更新する

最後のステップは、コンパイルされたコンテンツを共有ワーカーからプレビューに取得することです。設定はほぼ同じですが、関数はワーカー境界を越えて渡すことができないため、関数のプロキシを使用する必要があります。ここでも Comlink が役立ちます。js/preview.js を更新して、次の処理を行います。

  • comlink から名前付きエクスポート wrapproxy をインポートします。
  • js/main.js で行ったように、共有ワーカーを作成してラップします。
  • コンパイラの subscribe メソッドを呼び出し、受信データの compiled プロパティをプレビュー領域の内部 HTML に設定するプロキシ関数を渡します。

完了したら、プレビューを開き、エディタで入力を開始します。マークダウンが自動的にコンパイルされ、プレビュー領域にリアルタイムで表示される様子を楽しみましょう。どちらのページのメインスレッドもブロックされません。

6. 完了

共有ワーカーを使用して複数の PWA インスタンス間で状態を共有する方法について学習しました。