ワークボックス ウィンドウの使用

このドキュメントにはまだ記載されていない Workbox モジュールの一つに workbox-window があります。これは、window で実行することを目的としたモジュールのセットです。このモジュールの目標は次のとおりです。

  • デベロッパーが Service Worker のライフサイクルにおける重要な瞬間を特定し、その瞬間に対応できるようにすることで、Service Worker の登録と更新を簡素化します。
  • デベロッパーが誤ったスコープで Service Worker を登録するなど、よくあるミスを防ぐ。
  • windowService Worker スコープ間のメッセージングを簡素化するため。

workbox-window のインポートと使用

workbox-window から最も頻繁に使用するエクスポートは Workbox クラスです。このクラスは、Node でインポートすることも、ウェブページの CDN からインポートすることもできます。

ローカル バンドルの作成

ツールチェーンに webpackRollup などのバンドラが含まれている場合は、workbox-window をローカルでバンドルできます。

まず、workbox-window をアプリケーションの本番環境の依存関係としてインストールします。

npm install workbox-window --save

次に、アプリケーションの JavaScript で、workbox-window から Workbox クラスを import できます。

<script type="module">
import {Workbox} from 'workbox-window';

if ('serviceWorker' in navigator) {
  const wb = new Workbox('/sw.js');

  wb.register();
}
</script>

workbox-window は非常に小さいですが、動的 import を使用してウェブサイトのコア アプリケーション ロジックから分離できます。これにより、ページのメインバンドルのサイズを削減できます。

<script type="module">
if ('serviceWorker' in navigator) {
  const {Workbox} = await import('workbox-window');

  const wb = new Workbox('/sw.js');
  wb.register();
}
</script>

CDN の使用

推奨される方法ではありませんが、workbox-window を CDN からインポートする方法は簡単です。

<script type="module">
  import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.2.0/workbox-window.prod.mjs';

  if ('serviceWorker' in navigator) {
    const wb = new Workbox('/sw.js');

    wb.register();
  }
</script>

上記の例の <script> 要素では type="module" 属性を使用しています。これは、ビルドステップなしでブラウザで静的な import ステートメントを使用する場合に必要です。Service Worker をサポートするすべての主要なブラウザは JavaScript モジュールもサポートしています。そのため、古いブラウザでは type 属性値が "module"<script> 要素が無視されるため、このコードを任意のブラウザに配信しても問題ありません。

Service Worker の登録

workbox-window で Service Worker を登録するには、Workbox クラスの register メソッドを使用します。

import {Workbox} from 'workbox-window';

const wb = new Workbox('/sw.js');
wb.register();

これは、navigator.serviceWorker.register を使用して Service Worker を手動で登録するのと同じように思えます。ただし、Workbox.register は、window load イベントが発生するまで待機してから、Service Worker を登録します。この方法は、プリキャッシュが関係する状況で、ページ起動を遅らせる可能性のある帯域幅の競合を回避できる場合に便利です。

window と Service Worker スコープ間の通信

Service Worker には window とは別の独自のスコープがあり、window で利用可能な API のサブセットにのみアクセスできます。ただし、window とサービス ワーカーの間で通信することは可能です。workbox-window を使用すると、workbox-window モジュールの messageSW メソッドを使用して、2 つのスコープ間の通信を簡単に行うことができます。

Workbox はメッセージに特定の形式を使用します。次のプロパティを持つオブジェクトです。

  • type は、メッセージを一意に識別する必須の文字列です。形式は、単語をアンダースコアで区切った大文字にする必要があります(例: CACHE_URLS)。
  • meta は、メッセージの送信に使用するワークボックス パッケージの名前を表すオプションの文字列で、通常は省略されます。
  • payload は、送信するデータを表す省略可能なパラメータです。任意のデータ型を指定できます。

messageSW の仕組みの例を次に示します。まずは Service Worker のコードから開始します。

// sw.js
const SW_VERSION = '1.0.0';

self.addEventListener('message', (event) => {
  if (event.data.type === 'GET_VERSION') {
    event.ports[0].postMessage(SW_VERSION);
  }
});

ウェブページに次のコードを追加します。

const wb = new Workbox('/sw.js');
wb.register();

const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);

Service Worker のアップデートが利用可能になったらユーザーに通知するなど、Service Worker と window 間の通信はさまざまな場面で役に立ちます。このレシピは、messageSkipWaiting という self.skipWaiting の特別なヘルパー メソッドを利用しています。このメソッドは、type の値が SKIP_WAITING のメッセージを送信します。