このドキュメントでまだあまり説明していないワークボックス モジュールの一つが workbox-window
です。これは、window
で実行することを想定したモジュールのセットです。このモジュールの目標は次のとおりです。
- デベロッパーが Service Worker のライフサイクルの重要な瞬間を特定し、その瞬間に簡単に対応できるようにすることで、Service Worker の登録と更新を簡素化します。
- Service Worker を誤ったスコープで登録するなど、デベロッパーがよくあるミスを犯さないようにするため。
window
と Service Worker のスコープ間のメッセージングを簡素化するため。
workbox-window
のインポートと使用
workbox-window
から最もよく使用するエクスポートは Workbox
クラスです。これは、Node またはウェブページの CDN からインポートできます。
ローカル バンドルの作成
ツールチェーンに webpack や Rollup などのバンドラが含まれている場合は、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
は、Service Worker を登録する前に window
load
イベントまで待機します。これは、事前キャッシュが関係する状況で望ましい設定です。これにより、ページ起動を遅らせる可能性がある帯域幅の競合を回避できるからです。
window
と Service Worker のスコープ間の通信
Service Worker は window
とは別に独自のスコープを持ち、window
で使用可能な API のサブセットにのみアクセスできます。ただし、window
と Service Worker 間の通信は可能です。workbox-window
では、workbox-window
モジュールの messageSW
メソッドにより、2 つのスコープ間の通信が容易になります。
ワークボックスは、次のプロパティを持つオブジェクトとしてメッセージに特定の形式を使用します。
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 と window
間の通信が役立つケースは数多くあります。たとえば、Service Worker のアップデートが利用可能になったときにユーザーに通知します。このレシピは、messageSkipWaiting
という self.skipWaiting
の特別なヘルパー メソッドに依存しています。このメソッドは type
の値が SKIP_WAITING
のメッセージを送信します。