Service Worker は、ページのネットワーク リクエストをインターセプトできます。キャッシュされたコンテンツ、ネットワークのコンテンツ、Service Worker で生成されたコンテンツなどを使用してブラウザに応答します。
workbox-routing
は、レスポンスを提供するさまざまな関数にこれらのリクエストを簡単に「ルーティング」できるようにするモジュールです。
ルーティングの実行方法
ネットワーク リクエストによって Service Worker のフェッチ イベントが発生すると、workbox-routing
は指定されたルートとハンドラを使用してリクエストに応答しようとします。
上述の主な注意点は次のとおりです。
リクエストの方法は重要です。デフォルトでは、Route は
GET
リクエストに対して登録されます。他のタイプのリクエストをインターセプトする場合は、メソッドを指定する必要があります。ルートの登録順序は重要です。リクエストを処理できる複数の Route が登録されている場合は、最初に登録された Route がリクエストの処理に使用されます。
ルートを登録する方法はいくつかあり、コールバック、正規表現、Route インスタンスを使用できます。
ルートでの照合と処理
ワークボックスの「route」は、ルートがリクエストに一致するかどうかを判断する「マッチング」関数と、リクエストを処理してレスポンスを返す「処理」関数の 2 つの機能にすぎません。
Workbox にはマッチングと処理を行うヘルパーが用意されていますが、別の動作が必要な場合は、カスタムの一致とハンドラ関数を作成するのが最適です。
一致コールバック関数には、ExtendableEvent
、Request
、信頼できる値を返すことで照合できる URL
オブジェクトが渡されます。簡単な例として、次のように特定の URL を照合できます。
const matchCb = ({url, request, event}) => {
return url.pathname === '/special/url';
};
url
または request
を調査またはテストすることで、ほとんどのユースケースに対応できます。
ハンドラ コールバック関数には、同じ ExtendableEvent
、Request
、URL
オブジェクトと、params
値(match 関数によって返される値)が渡されます。
const handlerCb = async ({url, request, event, params}) => {
const response = await fetch(request);
const responseBody = await response.text();
return new Response(`${responseBody} <!-- Look Ma. Added Content. -->`, {
headers: response.headers,
});
};
ハンドラは、Response
に解決される Promise を返す必要があります。この例では、async
と await
を使用します。内部で、返される Response
値は Promise にラップされます。
これらのコールバックは次のように登録できます。
import {registerRoute} from 'workbox-routing';
registerRoute(matchCb, handlerCb);
唯一の制限は、「match」コールバックは同期的に真の値を返す必要があり、非同期処理は実行できません。これは、Router
がフェッチ イベントに同期的に応答するか、他のフェッチ イベントにフォールバックする必要があるためです。
通常、「ハンドラ」コールバックは、workbox-strategies によって提供される方法のいずれかを次のように使用します。
import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
registerRoute(matchCb, new StaleWhileRevalidate());
このページでは workbox-routing
を中心に説明しますが、ワークボックス戦略に関するこれらの戦略の詳細もご覧ください。
正規表現のルートの登録方法
一般的には、「match」コールバックの代わりに正規表現を使用します。Workbox を使用すると、次のように簡単に実装できます。
import {registerRoute} from 'workbox-routing';
registerRoute(new RegExp('/styles/.*\\.css'), handlerCb);
同じ送信元からのリクエストの場合、リクエストの URL が正規表現と一致する限り、この正規表現は一致します。
- https://example.com/styles/main.css
- https://example.com/styles/nested/file.css
- https://example.com/nested/styles/directory.css
ただし、クロスオリジン リクエストの場合、正規表現は URL の先頭と一致する必要があります。これは、正規表現 new RegExp('/styles/.*\\.css')
を使用するとサードパーティの CSS ファイルを照合できる可能性が低いためです。
- https://cdn.third-party-site.com/styles/main.css
- https://cdn.third-party-site.com/styles/nested/file.css
- https://cdn.third-party-site.com/nested/styles/directory.css
この動作が必要な場合は、正規表現が URL の先頭と一致するようにする必要があります。https://cdn.third-party-site.com
のリクエストを照合する場合は、正規表現 new RegExp('https://cdn\\.third-party-site\\.com.*/styles/.*\\.css')
を使用できます。
- https://cdn.third-party-site.com/styles/main.css
- https://cdn.third-party-site.com/styles/nested/file.css
- https://cdn.third-party-site.com/nested/styles/directory.css
ローカルとサードパーティの両方に一致する場合は、正規表現の先頭にワイルドカードを使用できますが、ウェブアプリで予期しない動作が発生しないように注意する必要があります。
ナビゲーション ルートを登録する方法
シングルページ アプリの場合は、NavigationRoute
を使用して、すべてのナビゲーション リクエストに対して特定のレスポンスを返すことができます。
import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';
// This assumes /app-shell.html has been precached.
const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler);
registerRoute(navigationRoute);
ユーザーがブラウザでサイトにアクセスすると、そのページのリクエストはナビゲーション リクエストとなり、キャッシュされたページ /app-shell.html
が配信されます。(注: workbox-precaching
または独自のインストール手順で、ページをキャッシュに保存する必要があります)。
デフォルトでは、すべてのナビゲーション リクエストに応答します。一部の URL にのみレスポンスを返すように制限する場合は、allowlist
オプションと denylist
オプションを使用して、このルートに一致するページを制限できます。
import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';
// This assumes /app-shell.html has been precached.
const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler, {
allowlist: [new RegExp('/blog/')],
denylist: [new RegExp('/blog/restricted/')],
});
registerRoute(navigationRoute);
ただし、URL が allowlist
と denylist
の両方にある場合、denylist
が優先されます。
デフォルト ハンドラの設定
ルートに一致しないリクエストに「ハンドラ」を提供する場合は、デフォルト ハンドラを設定できます。
import {setDefaultHandler} from 'workbox-routing';
setDefaultHandler(({url, event, params}) => {
// ...
});
キャッチ ハンドラを設定する
いずれかのルートでエラーがスローされた場合は、キャッチ ハンドラを設定することで、キャプチャとグレースフル デグラデーションを行うことができます。
import {setCatchHandler} from 'workbox-routing';
setCatchHandler(({url, event, params}) => {
...
});
GET 以外のリクエスト用のルートの定義
デフォルトでは、すべてのルートが GET
リクエスト用のものとみなされます。
POST
リクエストなど、他のリクエストをルーティングする場合は、ルートの登録時に次のようにメソッドを定義する必要があります。
import {registerRoute} from 'workbox-routing';
registerRoute(matchCb, handlerCb, 'POST');
registerRoute(new RegExp('/api/.*\\.json'), handlerCb, 'POST');
ルーターのロギング
workbox-routing
のログを使用して、リクエストのフローを特定できます。このログには、Workbox で処理されている URL がハイライト表示されます。
より詳細な情報が必要な場合は、ログレベルを debug
に設定すると、Router で処理されないリクエストのログを表示できます。ログレベルの設定の詳細については、デバッグガイドをご覧ください。
高度な使用方法
ワークボックス ルーターにリクエストが提供されるタイミングをより細かく制御するには、独自の Router
インスタンスを作成し、ルーターを使用してリクエストに応答する必要があるときに、そのインスタンスの handleRequest()
メソッドを呼び出します。
import {Router} from 'workbox-routing';
const router = new Router();
self.addEventListener('fetch', event => {
const {request} = event;
const responsePromise = router.handleRequest({
event,
request,
});
if (responsePromise) {
// Router found a route to handle the request.
event.respondWith(responsePromise);
} else {
// No route was found to handle the request.
}
});
Router
を直接使用する場合は、Route
クラスか、いずれかの拡張クラスを使用してルートを登録する必要もあります。
import {Route, RegExpRoute, NavigationRoute, Router} from 'workbox-routing';
const router = new Router();
router.registerRoute(new Route(matchCb, handlerCb));
router.registerRoute(new RegExpRoute(new RegExp(...), handlerCb));
router.registerRoute(new NavigationRoute(handlerCb));
型
NavigationRoute
NavigationRoute を使用すると、ブラウザ [ナビゲーション リクエスト]https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests
に一致する workbox-routing.Route
を簡単に作成できます。
https://fetch.spec.whatwg.org/#concept-request-mode|mode
が navigate
に設定されている受信リクエストにのみ一致します。
このルートは、denylist
パラメータと allowlist
パラメータのいずれかまたは両方を使用して、ナビゲーション リクエストのサブセットにのみ適用することもできます。
プロパティ
-
void
denylist
とallowlist
の両方を指定すると、denylist
が優先され、リクエストはこのルートと一致しません。allowlist
とdenylist
の正規表現は、リクエストされた URL の連結された [pathname
]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname
と [search
]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search
の部分と照合されます。注: これらの RegExp は、ナビゲーション中にすべてのリンク先 URL に対して評価される場合があります。複雑な RegExps は使用しないでください。ユーザーがサイトを移動する際に遅延が発生する可能性があるためです。
constructor
関数は次のようになります。(handler: RouteHandler, options?: NavigationRouteMatchOptions) => {...}
-
Response を返す Promise を返すコールバック関数。
-
-
HTTPMethod
-
void
setCatchHandler
関数は次のようになります。(handler: RouteHandler) => {...}
-
レスポンスに解決される Promise を返すコールバック関数
-
NavigationRouteMatchOptions
プロパティ
-
RegExp[](省略可)
-
RegExp[](省略可)
RegExpRoute
RegExpRoute を使用すると、正規表現ベースの workbox-routing.Route
を簡単に作成できます。
同一オリジンのリクエストの場合、RegExp で一致させる必要があるのは URL の一部のみです。サードパーティのサーバーに対するリクエストでは、URL の先頭に一致する RegExp を定義する必要があります。
プロパティ
-
コンストラクタ
void
正規表現に [キャプチャ グループ]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references
が含まれている場合、キャプチャされた値はworkbox-routing~handlerCallback
params
引数に渡されます。constructor
関数は次のようになります。(regExp: RegExp, handler: RouteHandler, method?: HTTPMethod) => {...}
-
regExp
RegExp
URL と照合する正規表現。
-
handler
Response を返す Promise を返すコールバック関数。
-
method
HTTPMethod 省略可
-
戻り値
-
-
catchHandler
-
handler
-
method
HTTPMethod
-
setCatchHandler
void
setCatchHandler
関数は次のようになります。(handler: RouteHandler) => {...}
-
handler
レスポンスに解決する Promise を返すコールバック関数
-
Route
Route
は、コールバック関数「match」と「handler」のペアで構成されます。「match」コールバックは、可能であれば falsy でない値を返して、リクエストを「処理」するためにルートを使用する必要があるかどうかを判断します。「handler」コールバックは、一致があると呼び出され、Response
に解決される Promise を返します。
プロパティ
-
コンストラクタ
void
Route クラスのコンストラクタ。
constructor
関数は次のようになります。(match: RouteMatchCallback, handler: RouteHandler, method?: HTTPMethod) => {...}
-
falsy でない値を返して、経路が特定の
fetch
イベントに一致するかどうかを判断するコールバック関数。 -
handler
レスポンスに解決される Promise を返すコールバック関数。
-
method
HTTPMethod 省略可
-
戻り値
-
-
catchHandler
-
handler
-
method
HTTPMethod
-
setCatchHandler
void
setCatchHandler
関数は次のようになります。(handler: RouteHandler) => {...}
-
handler
レスポンスに解決する Promise を返すコールバック関数
-
Router
Router は、1 つ以上の workbox-routing.Route
を使用して FetchEvent
を処理するために使用できます。一致するルートが存在する場合は、Response
で応答します。
リクエストに一致するルートがない場合、Router は「default」ハンドラを使用します(定義されている場合)。
一致する Route がエラーをスローすると、Router は「catch」ハンドラを使用します(定義されている場合)。catch ハンドラは問題に適切に対処し、リクエストに応答します。
リクエストが複数のルートに一致する場合、リクエストへのレスポンスには登録されている最も早いルートが使用されます。
プロパティ
-
コンストラクタ
void
新しい Router を初期化します。
constructor
関数は次のようになります。() => {...}
-
戻り値
-
-
ルート
Map<HTTPMethodRoute[]>
-
addCacheListener
void
ウィンドウからキャッシュに保存する URL のメッセージ イベント リスナーを追加します。これは、Service Worker が制御を開始する前にページに読み込まれたリソースをキャッシュに保存する場合に便利です。
ウィンドウから送信されるメッセージ データの形式は次のとおりです。 ここで、
urlsToCache
配列は、URL 文字列、または URL 文字列とrequestInit
オブジェクトの配列(fetch()
に渡す場合と同じ)で構成されます。{ type: 'CACHE_URLS', payload: { urlsToCache: [ './script1.js', './script2.js', ['./script3.js', {mode: 'no-cors'}], ], }, }
addCacheListener
関数は次のようになります。() => {...}
-
addFetchListener
void
フェッチ イベント リスナーを追加して、ルートがイベントのリクエストと一致するとイベントに応答します。
addFetchListener
関数は次のようになります。() => {...}
-
findMatchingRoute
void
リクエストと URL(必要に応じてイベント)を登録済みルートのリストと照合し、一致する場合は、対応するルートを一致によって生成されたパラメータとともに返します。
findMatchingRoute
関数は次のようになります。(options: RouteMatchCallbackOptions) => {...}
-
戻り値
オブジェクト
route
プロパティとparams
プロパティを持つオブジェクト。 一致するルートが見つかった場合は値が入力され、見つからなかった場合はundefined
が設定されます。
-
-
handleRequest
void
FetchEvent オブジェクトにルーティング ルールを適用して、適切な Route のハンドラから Response を取得します。
handleRequest
関数は次のようになります。(options: object) => {...}
-
オプション
オブジェクト
-
event
ExtendableEvent
リクエストをトリガーしたイベント。
-
request
リクエスト
処理するリクエスト。
-
-
戻り値
Promise<Response>
登録されたルートがリクエストを処理できる場合は Promise が返されます一致するルートがなく、
defaultHandler
もない場合は、undefined
が返されます。
-
-
registerRoute
void
ルーターにルートを登録します。
registerRoute
関数は次のようになります。(route: Route) => {...}
-
経路
登録するルート。
-
-
setCatchHandler
void
リクエストの処理中に Route がエラーをスローすると、この
handler
が呼び出され、レスポンスを提供する機会が与えられます。setCatchHandler
関数は次のようになります。(handler: RouteHandler) => {...}
-
handler
Response を返す Promise を返すコールバック関数。
-
-
setDefaultHandler
void
受信リクエストに明示的に一致するルートがない場合に呼び出されるデフォルトの
handler
を定義します。各 HTTP メソッド(GET、POST など)は、それぞれ独自のデフォルト ハンドラを取得します。
デフォルト ハンドラがない場合、一致しないリクエストは、Service Worker が存在しないものとしてネットワークに送信されます。
setDefaultHandler
関数は次のようになります。(handler: RouteHandler, method?: HTTPMethod) => {...}
-
handler
Response を返す Promise を返すコールバック関数。
-
method
HTTPMethod 省略可
-
-
unregisterRoute
void
ルーターへのルートの登録を解除します。
unregisterRoute
関数は次のようになります。(route: Route) => {...}
-
経路
登録を解除するルート。
-
メソッド
registerRoute()
workbox-routing.registerRoute(
capture: string | RegExp | RouteMatchCallback | Route,
handler?: RouteHandler,
method?: HTTPMethod,
)
シングルトン Router インスタンスに、キャッシュ戦略を使用する RegExp、文字列、関数を簡単に登録できます。
このメソッドは、必要に応じて Route を生成し、workbox-routing.Router#registerRoute
を呼び出します。
パラメータ
-
キャプチャ
string | RegExp | RouteMatchCallback | ルート
キャプチャ パラメータが
Route
の場合、他のすべての引数は無視されます。 -
handler
RouteHandler 省略可
-
method
HTTPMethod 省略可
戻り値
-
生成された
Route
。
setCatchHandler()
workbox-routing.setCatchHandler(
handler: RouteHandler,
)
リクエストの処理中に Route がエラーをスローすると、この handler
が呼び出され、レスポンスを提供する機会が与えられます。
パラメータ
-
handler
Response を返す Promise を返すコールバック関数。
setDefaultHandler()
workbox-routing.setDefaultHandler(
handler: RouteHandler,
)
受信リクエストに明示的に一致するルートがない場合に呼び出されるデフォルトの handler
を定義します。
デフォルト ハンドラがない場合、一致しないリクエストは、Service Worker が存在しないものとしてネットワークに送信されます。
パラメータ
-
handler
Response を返す Promise を返すコールバック関数。