Service Worker を使用してページの更新をブロードキャストする

Andrew Guan
Andrew Guan

状況によっては、Service Worker がアクティブな 特定のイベントを知らせることができます。次に例を示します。

  • Service Worker の新しいバージョンがインストールされたら、ページを通知して、 新機能にアクセスするための「更新して更新」ボタンをユーザーに表示する すぐに通知されます。
  • Service Worker 側で行われたキャッシュ データの変更を、次の方法でユーザーに通知します。 「The app is now ready to work offline」「 content available」と表示できます
Service Worker がページと通信して更新を送信している様子を示す図。

このようなユースケースを、Service Worker が Google Cloud からの コミュニケーション「最新情報のブロードキャスト」を開始できます。このガイドでは、Chronicle の ページと Service Worker 間でこのタイプの通信を実装するには、標準の ブラウザ API と Workbox ライブラリがあります。

本番環境のケース

Tinder

Tinder PWA は workbox-window を使用してリッスンします Service Worker のライフサイクルに関する重要な瞬間を 「有効」など)。こうすることで、新しい Service Worker が登場したときに「Update Available」と表示されます バナーが表示され、ユーザーは PWA を更新して最新機能を利用できるようになります。

<ph type="x-smartling-placeholder">
</ph> Tinder のウェブアプリ「Update Available」のスクリーンショット説明します。
Tinder PWA では、新しいバージョンが準備完了であることを Service Worker が通知し、「アップデート利用可能」と表示されます。なります。

スクオッシュ

Squoosh PWA では、Service Worker が必要なすべての情報を オフラインで使用できるようにすると、ページに「オフラインで使用可」であることを示すメッセージがページに送信されます。 トーストし、その機能についてユーザーに知らせます。

<ph type="x-smartling-placeholder">
</ph> Squoosh ウェブアプリ「Ready to work offline」のスクリーンショット説明します。
Squoosh PWA では、キャッシュの準備が整うと Service Worker がページに更新をブロードキャストし、ページに「オフラインで作業可能」と表示されますあります。

ワークボックスの使用

Service Worker のライフサイクル イベントをリッスンする

workbox-window は、Service Worker の重要なライフサイクルをリッスンできるわかりやすいインターフェースを提供します。 できます。 内部的には、ライブラリは次のようなクライアントサイド API を使用します。 updatefoundstatechange また、workbox-window オブジェクトで上位レベルのイベント リスナーが提供されるため、 イベントを使用できます

次のページコードを使用すると、新しいバージョンの Service Worker がインストールされるたびに、 これをユーザーに伝えることができます。

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

wb.addEventListener('installed', (event) => {
  if (event.isUpdate) {
    // Show "Update App" banner
  }
});

wb.register();

キャッシュ データの変更をページに通知する

Workbox パッケージ workbox-broadcast-update は、キャッシュされたレスポンスが更新されたことをウィンドウ クライアントに通知する標準的な方法を提供します。これは、 StalewhileRevalidate とともによく使用されるもの 戦略をご覧ください。

最新情報をブロードキャストするには、broadcastUpdate.BroadcastUpdatePlugin Service Worker 側:

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';

registerRoute(
  ({url}) => url.pathname.startsWith('/api/'),
  new StaleWhileRevalidate({
    plugins: [
      new BroadcastUpdatePlugin(),
    ],
  })
);

ウェブアプリでは、次のようにしてこれらのイベントをリッスンできます。

navigator.serviceWorker.addEventListener('message', async (event) => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.data.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;

    // Do something with cacheName and updatedUrl.
    // For example, get the cached content and update
    // the content on the page.
    const cache = await caches.open(cacheName);
    const updatedResponse = await cache.match(updatedUrl);
    const updatedText = await updatedResponse.text();
  }
});

ブラウザの API を使用する

Workbox の機能ではニーズを満たせない場合は、次のブラウザを使用してください 「ブロードキャスト アップデート」を実装するための API:

Broadcast Channel API

Service Worker が BroadcastChannel を作成する オブジェクトが生成され、 追加できます。これらのメッセージの受信に関係のあるコンテキスト(ページなど)で、 BroadcastChannel オブジェクトを作成し、メッセージを受信するためのメッセージ ハンドラを実装します。

新しい Service Worker のインストールをページに通知するには、次のコードを使用します。

// Create Broadcast Channel to send messages to the page
const broadcast = new BroadcastChannel('sw-update-channel');

self.addEventListener('install', function (event) {
  // Inform the page every time a new service worker is installed
  broadcast.postMessage({type: 'CRITICAL_SW_UPDATE'});
});

このページは、sw-update-channel に登録することで、これらのイベントをリッスンします。

// Create Broadcast Channel and listen to messages sent to it
const broadcast = new BroadcastChannel('sw-update-channel');

broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'CRITICAL_SW_UPDATE') {
    // Show "update to refresh" banner to the user.
  }
};

これは単純な手法ですが、ブラウザのサポートが限られています。このドキュメントの作成時点では、 Safari はこの API をサポートしていません

Client API

Client API: Service Worker から複数のクライアントと通信するには、 Client オブジェクト。

次の Service Worker コードを使用して、最後にフォーカスされたタブにメッセージを送信します。

// Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
  if (clients && clients.length) {
    // Respond to last focused tab
    clients[0].postMessage({type: 'MSG_ID'});
  }
});

このページには、これらのメッセージをインターセプトするメッセージ ハンドラが実装されています。

// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
     if (event.data && event.data.type === 'MSG_ID') {
         // Process response
   }
};

Client API は、複数のアクティブなタブに情報をブロードキャストする場合などに適しています。「 API は主要なブラウザでサポートされていますが、すべてのメソッドがサポートされているわけではありません。次の日付より前にブラウザのサポートを確認する できます。

メッセージ チャンネル

メッセージ チャネルの要件 最初の構成ステップとして、ページから Service Worker にポートを渡して、 通信チャネルを確立します。このページは MessageChannel オブジェクトをインスタンス化し、 postMessage() インターフェースを介して Service Worker にポートをルーティングします。

const messageChannel = new MessageChannel();

// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

このページでメッセージをリッスンするために、ハンドラを実行します。

// Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};

Service Worker はポートを受け取り、そのポートへの参照を保存します。

// Initialize
let communicationPort;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PORT_INITIALIZATION') {
    communicationPort = event.ports[0];
  }
});

その時点から、postMessage() を呼び出してページにメッセージを送信できます。 port:

// Communicate
communicationPort.postMessage({type: 'MSG_ID' });

MessageChannel はポートを初期化する必要があるため、実装が複雑になる可能性がありますが、 すべての主要ブラウザでサポートされています。

次のステップ

このガイドでは、Window から Service Worker への通信の特定のケースについて説明しました。 "ブロードキャスト更新"。取り上げた例には、重要な Service Worker のリッスンが含まれます。 コンテンツの変更やキャッシュ データの変更に関するページへの通信も可能です。このように考えれば Service Worker がページとプロアクティブに通信する という興味深いユースケースがあります メッセージが送られてこないからです

ウィンドウと Service Worker の通信のその他のパターンについては、以下をご覧ください。

  • 命令型キャッシュに関するガイド: ページから Service Worker を呼び出して 事前にリソースをキャッシュに保存します(プリフェッチのシナリオなど)。
  • 双方向通信: タスクを Service Worker に委任する(例: 読み込みの負荷が大きくなるなど)、進行状況はページに継続的に報告されます。

参考情報