Service Worker の操作

この Codelab では、ウェブ アプリケーション内からサービス ワーカーを登録し、Chrome DevTools を使用してその動作を観察する方法について説明します。また、サービス ワーカーを扱う際に役立つデバッグ手法についても説明します。

サンプル プロジェクトを理解する

この Codelab に最も関連するサンプル プロジェクトのファイルは次のとおりです。

  • register-sw.js は最初は空ですが、サービス ワーカーの登録に使用されるコードが含まれます。プロジェクトの index.html 内の <script> タグを介してすでに読み込まれています。
  • service-worker.js も同様に空です。このプロジェクトのサービス ワーカーを含むファイルです。

Service Worker 登録コードを追加する

サービス ワーカー(現在の service-worker.js ファイルのような空のワーカーでも)は、最初に登録されない限り使用されません。これを行うには、次の呼び出しを行います。

navigator.serviceWorker.register(
  '/service-worker.js'
)

register-sw.js ファイル内に

ただし、そのコードを追加する前に、考慮すべき点がいくつかあります。

まず、すべてのブラウザが Service Worker をサポートしているわけではありません。これは、自動的に更新されない古いバージョンのブラウザで特に当てはまります。そのため、navigator.serviceWorker がサポートされているかどうかを確認してから、条件付きで navigator.serviceWorker.register() を呼び出すことをおすすめします。

次に、サービス ワーカーを登録すると、ブラウザは service-worker.js ファイル内のコードを実行します。サービス ワーカーの install イベント ハンドラと activate イベント ハンドラのコードによっては、キャッシュを読み込むために URL のダウンロードを開始する可能性があります。

追加のコードを実行したりアセットをダウンロードしたりすると、ブラウザが現在のウェブページを表示するために使用できる貴重なリソースが消費される可能性があります。この干渉を回避するには、ブラウザが現在のページのレンダリングを完了するまで、サービス ワーカーの登録を遅らせることをおすすめします。この近似値を求める便利な方法として、window.load イベントが発火するまで待機する方法があります。

この 2 つのポイントをまとめると、次の汎用サービス ワーカー登録コードを register-sw.js ファイルに追加することになります。

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js');
  });
}

Service Worker のロギング コードを追加する

service-worker.js ファイルには、通常、サービス ワーカーの実装に関するすべてのロジックが記述されます。サービス ワーカーのライフサイクル イベントCache Storage API、ウェブアプリのネットワーク トラフィックに関する知識を組み合わせて、ウェブアプリのすべてのリクエストを処理できる完璧なサービス ワーカーを作成します。

ただし、これらは後で学習します。この段階では、さまざまなサービス ワーカー イベントを観察し、Chrome の DevTools を使用してサービス ワーカーの状態をデバッグすることに慣れることに重点を置きます。

そのため、service-worker.js に次のコードを追加します。これにより、さまざまなイベントに応じて DevTools コンソールにメッセージが記録されます(ただし、それ以外の処理はほとんど行われません)。

self.addEventListener('install', (event) => {
  console.log('Inside the install handler:', event);
});

self.addEventListener('activate', (event) => {
  console.log('Inside the activate handler:', event);
});

self.addEventListener(fetch, (event) => {
  console.log('Inside the fetch handler:', event);
});

DevTools の [Service Workers] パネルについて

register-sw.js ファイルと service-worker.js ファイルにコードを追加したので、サンプル プロジェクトのライブ バージョンにアクセスして、サービス ワーカーの動作を確認します。

  • サイトをプレビューするには、[アプリを表示] を押し、[全画面表示] 全画面表示 を押します。
  • `Ctrl+Shift+J`(Mac の場合は `Command+Option+J`)を押して、デベロッパー ツールを開きます。
  • [コンソール] タブをクリックします。

次のようなログメッセージが表示され、サービス ワーカーがインストールされて有効になっていることがわかります。

Service Worker がインストールされ、有効になっていることを示します。

次に、[アプリケーション] タブに移動し、[サービス ワーカー] パネルを選択します。次のような画面が表示されます。

サービス ワーカー パネルにサービス ワーカーの詳細を表示します。

これは、ウェブアプリ solar-donkey.glitch.me のソース URL が service-worker.js のサービス ワーカーが現在アクティブ化されて実行されていることを示しています。また、現在 Service Worker によって制御されているクライアント(開いているタブ)が 1 つあることも示しています。

このパネルのリンク(Unregisterstop など)を使用して、デバッグ目的で現在登録されているサービス ワーカーを変更できます。

サービス ワーカーの更新フローをトリガーする

サービス ワーカーを使用して開発する際に理解すべき重要なコンセプトの 1 つは、更新フローの考え方です。

サービス ワーカーを登録するウェブアプリにアクセスすると、ユーザーのローカル ブラウザに service-worker.js の現在のコピーのコードがインストールされます。しかし、ウェブサーバーに保存されている service-worker.js のバージョンを更新するとどうなるでしょうか?

リピーターがサービス ワーカーのスコープ内の URL に戻ると、ブラウザは自動的に最新の service-worker.js をリクエストし、変更がないか確認します。サービス ワーカー スクリプトのいずれかが異なる場合、新しいサービス ワーカーはインストール、アクティブ化、最終的な制御の機会を得ます。

この更新フローをシミュレートするには、プロジェクトのコードエディタに戻り、コードに任意の変更を加えます。1 つの簡単な変更は、

self.addEventListener('install', (event) => {
  console.log('Inside the install handler:', event);
});

self.addEventListener('install', (event) => {
  console.log('Inside the UPDATED install handler:', event);
});

変更を加えたら、サンプルアプリのライブ バージョンに戻り、DevTools の [アプリケーション] タブを開いたままページを再読み込みします。次のような画面が表示されます。

インストールされている Service Worker の 2 つのバージョンが表示されます。

この時点で、サービス ワーカーのバージョンが 2 つインストールされていることがわかります。すでに有効になっている以前のバージョンが実行されており、現在のページを制御しています。更新されたサービス ワーカーのバージョンは、次のとおりです。waiting 状態になり、古いサービス ワーカーによって制御されている開いているタブがすべて閉じられるまで待機します。

このデフォルトの動作により、新しいサービス ワーカーの動作が古いサービス ワーカーと根本的に異なる場合(古いバージョンのウェブアプリと互換性のないリソースで応答する fetch ハンドラなど)、ユーザーがウェブアプリの以前のインスタンスをすべてシャットダウンするまで、新しいサービス ワーカーは有効になりません。

まとめ

これで、サービス ワーカーを登録し、Chrome の DevTools を使用してサービス ワーカーの動作を観察するプロセスに慣れたはずです。

これで、キャッシュ保存戦略や、ウェブアプリの読み込みを確実かつ高速に行うためのさまざまな機能を実装する準備が整いました。