Advanced
Service workers
Edit this page on GitHubService Worker は、アプリ内部でネットワークリクエストを処理するプロキシサーバーとして機能します。これによりアプリをオフラインで動作させることが可能になります。もしオフラインサポートが不要な場合(または構築するアプリの種類によって現実的に実装できない場合)でも、ビルドした JS と CSS を事前にキャッシュしてナビゲーションを高速化するために Service Worker を使用する価値はあります。
SvelteKit では、src/service-worker.js
ファイル (や src/service-worker/index.js
) がある場合、バンドルされ、自動的に登録されます。必要に応じて、service worker の ロケーション を変更することができます。
service worker を独自のロジックで登録する必要がある場合や、その他のソリューションを使う場合は、自動登録を無効化 することができます。デフォルトの登録方法は次のようなものです:
ts
if ('serviceWorker' innavigator ) {addEventListener ('load', function () {navigator .serviceWorker .register ('./path/to/service-worker.js');});}
service worker の内部ではpermalink
service worker の内部では、$service-worker
モジュール にアクセスでき、これによって全ての静的なアセット、ビルドファイル、プリレンダリングページへのパスが提供されます。また、アプリのバージョン文字列 (一意なキャッシュ名を作成するのに使用できます) と、デプロイメントの base
パスが提供されます。Vite の設定に define
(グローバル変数の置換に使用) を指定している場合、それはサーバー/クライアントのビルドだけでなく、service worker にも適用されます。
次の例では、ビルドされたアプリと static
にあるファイルをすぐに(eagerly)キャッシュし、その他全てのリクエストはそれらの発生時にキャッシュします。これにより、各ページは一度アクセスするとオフラインで動作するようになります。
ts
/// <reference types="@sveltejs/kit" />import {build ,files ,version } from '$service-worker';// Create a unique cache name for this deploymentconstCACHE = `cache-${version }`;constASSETS = [...build , // the app itself...files // everything in `static`];self .addEventListener ('install', (event ) => {// Create a new cache and add all files to itasync functionaddFilesToCache () {constProperty 'waitUntil' does not exist on type 'Event'.2339Property 'waitUntil' does not exist on type 'Event'.cache = awaitcaches .open (CACHE );awaitcache .addAll (ASSETS );}event .waitUntil (addFilesToCache ());});self .addEventListener ('activate', (event ) => {// Remove previous cached data from diskasync functiondeleteOldCaches () {for (constkey of awaitcaches .keys ()) {if (Property 'waitUntil' does not exist on type 'Event'.2339Property 'waitUntil' does not exist on type 'Event'.key !==CACHE ) awaitcaches .delete (key );}}event .waitUntil (deleteOldCaches ());});Property 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.self .addEventListener ('fetch', (event ) => {// ignore POST requests etcProperty 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.if (event .request .method !== 'GET') return;async functionrespond () {consturl = newURL (event .request .url );constcache = awaitcaches .open (CACHE );// `build`/`files` can always be served from the cacheif (ASSETS .includes (url .pathname )) {constresponse = awaitcache .match (url .pathname );if (response ) {returnresponse ;}}Property 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.// for everything else, try the network first, but// fall back to the cache if we're offlinetry {constresponse = awaitfetch (event .request );// if we're offline, fetch can return a value that is not a Response// instead of throwing - and we can't pass this non-Response to respondWithif (!(response instanceofResponse )) {throw newProperty 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.Error ('invalid response from fetch'); }if (response .status === 200) {cache .put (event .request ,response .clone ());}Property 'request' does not exist on type 'Event'.2339Property 'request' does not exist on type 'Event'.returnresponse ;} catch (err ) {constresponse = awaitcache .match (event .request );if (response ) {returnresponse ;}// if there's no cache, then just error out// as there is nothing we can do to respond to this requestthrowProperty 'respondWith' does not exist on type 'Event'.2339Property 'respondWith' does not exist on type 'Event'.err ;}}event .respondWith (respond ());});
キャッシュにはご注意ください! 場合によっては、オフラインでは利用できないデータよりも古くなったデータのほうが悪いことがあります。ブラウザはキャッシュが一杯になると空にするため、ビデオファイルのような大きなアセットをキャッシュする場合にもご注意ください。
開発中は(During development)permalink
service worker はプロダクション向けにはバンドルされますが、開発中はバンドルされません。そのため、modules in service workers をサポートするブラウザのみ、開発時にもそれを使用することができます。service worker を手動で登録する場合、開発時に { type: 'module' }
オプションを渡す必要があります:
ts
import {dev } from '$app/environment';navigator .serviceWorker .register ('/service-worker.js', {type :dev ? 'module' : 'classic'});
build
とprerendered
は開発中は空配列です
型安全性(Type safety)permalink
service worker に適切な型を設定するには、マニュアルで設定が必要です。service-worker.js
の中で、ファイルの先頭に以下を追加してください:
ts
/// <reference types="@sveltejs/kit" />/// <reference no-default-lib="true"/>/// <reference lib="esnext" />/// <reference lib="webworker" />constsw = /** @type {ServiceWorkerGlobalScope} */ (/** @type {unknown} */ (self ));
ts
/// <reference types="@sveltejs/kit" />/// <reference no-default-lib="true"/>/// <reference lib="esnext" />/// <reference lib="webworker" />constsw =self as unknown asServiceWorkerGlobalScope ;
これにより、HTMLElement
のような service worker の中では使用できない DOM の型付けへのアクセスが無効になり、正しい global が初期化されます。self
を sw
に再代入することで、プロセス内で型をキャストすることができます (いくつか方法がありますが、これが追加のファイルを必要としない最も簡単な方法です)。ファイルの残りの部分では、self
の代わりに sw
を使用します。SvelteKit の型を参照することで、$service-worker
import に適切な型定義があることを保証することができます。もし $env/static/public
をインポートする場合は、そのインポートに // @ts-ignore
を追加するか、/// <reference types="../.svelte-kit/ambient.d.ts" />
を reference types に追加する必要があります。
その他のソリューションpermalink
SvelteKit の service worker 実装は意図的に低レベル(low-level)です。より本格的な、よりこだわりが強い(opinionated)ソリューションが必要な場合は、Vite PWA plugin のようなソリューションをご覧になることをおすすめしております、こちらは Workbox を使用しています。service worker に関する一般的な情報をもっとお探しであれば、MDN web docs をおすすめします。