キャッシュによるオフライン表示をサポートするAngularのService Worker
Service Workerは、Webページと独立してバックグラウンドで動作するJavaScriptです。Angularでは、ネットワーク接続なしでWebページを表示できるService Workerのキャッシュ機能を、より利用しやすくする機能が提供されます。
AngularのService Worker設定
AngularのService Worker機能は、「@angular/service-worker」パッケージで提供されます。「ng add」コマンドでPWA機能を追加すると、モジュール定義ファイル(app.module.ts)にService Workerの設定が自動的に追加されます。
import { ServiceWorkerModule } from '@angular/service-worker'; // ...(1)
(略)
@NgModule({
(略)
imports: [
BrowserModule,
ServiceWorkerModule.register('ngsw-worker.js',
{ enabled: environment.production }) // ...(2)
],
(略)
(1)で参照したServiceWorkerModuleを利用して、(2)でService Workerを設定します。この設定では、本番ビルド設定(environment.production)のときだけ、「ngsw-worker.js」というファイル名でService WorkerのJavaScriptを配置します。
リスト5の設定によって、ngsw-worker.jsがビルド後のファイルに含まれるようになり、Service Workerとして実行されます。開発者が自分でService Workerを実装する必要はありません。
AngularのService Workerが提供するキャッシュ機能
PWA機能を追加したAngularのWebアプリでは、Service Workerによって、以下のファイルが自動的にキャッシュされます。そのため、一度Webページを表示してキャッシュしておけば、ネットワーク接続がなくても、同じURLでWebページを再表示できます。
- index.html
- favicon.ico
- ビルドで生成されたJavaScriptやCSSファイル
- assetsフォルダー配下のファイル(画像ファイルなど)
なお、Chromeブラウザーでは、F12キーで起動できるデベロッパーツールの「Network」タブで「Offline」をチェックすると、ネットワーク接続がない状態にできます。この状態でページを再読込すると、画面下部の取得ファイル一覧に「from ServiceWorker」と表示されて、Service Workerによるキャッシュが有効になっていることが確認できます。
キャッシュの自動更新と手動更新
Service Workerを利用したキャッシュ機能を開発者が自分で実装する場合、複数ファイルの整合性を保ちながらキャッシュを保持・更新するのは開発者の責任です。それに対してAngularのキャッシュ機能では、キャッシュの管理が自動化されます。Webページのファイル更新を検知すると、整合性を維持しながらキャッシュを更新してくれます。
更新確認や更新処理は、Webページの表示時に自動で行われますが、別のタイミングで明示的に実行することもできます。図13のサンプルでは、30秒間隔で更新確認をして、更新が見つかったら利用者に更新を促します。
コンポーネントに実装した更新処理はリスト6です。
// コンストラクターでSwUpdateのオブジェクトを受け取る ...(1)
constructor(private updates: SwUpdate) {
// 更新が見つかったときの処理 ...(2)
this.updates.available.subscribe(event => {
alert('新しいコンテンツが見つかりました。更新します。');
this.updates.activateUpdate(); // 更新を実行 ...(3)
});
// 更新が完了したときの処理 ...(4)
this.updates.activated.subscribe(event => {
alert('コンテンツが更新されました。ページを再読込します。');
document.location.reload();
});
// Service Workerが準備できてから実行 ...(5)
navigator.serviceWorker.ready.then(() => {
// 30秒に1回更新確認を行う処理 ...(6)
setInterval(() => {
this.updates.checkForUpdate(); // 更新を確認 ...(7)
}, 30 * 1000);
});
}
Angularのキャッシュ更新処理を提供するSwUpdateのオブジェクトupdatesを、(1)のコンストラクターで、依存性注入を利用して受け取ります。
更新が見つかったときの処理は(2)のupdates.available、更新完了時の処理は(4)のupdates.activatedに、それぞれ記述します。ここでは、更新が見つかったら(3)のupdate.activateUpdateメソッドで更新を実行して、完了したらページを再読込するように実装しています。
(5)のnavigator.serviceWorker.ready.thenメソッドで、Service Workerの準備ができているのを確認してから、(6)の更新確認処理を開始します。ここでは30秒に1回、(7)のupdates.checkForUpdateメソッドで更新を確認します。
リスト6の処理を確認するには、WebブラウザーにWebページを表示させたまま、コンポーネントのテンプレートファイルをリスト7のように書き換えたあと、「npm run pwa」コマンドで再ビルド/Webページ公開します。
<!-- 変更前 --> <!-- <img src="../assets/images/main_picture_1.jpg" width="480px"> --> <!-- 変更後 --> <img src="../assets/images/main_picture_2.jpg" width="480px">
しばらくすると、リスト6(2)の処理が更新を検知して、確認ダイアログを表示します。(3)の処理で更新を実行して、完了すると(4)の処理でページが再読込されます。
キャッシュするファイルの設定
AngularのService Worker機能でキャッシュするファイルは、ngsw-config.jsonファイルで定義されています。デフォルトのngsw-config.jsonファイルをリスト8に示します。
{
"index": "/index.html",
"assetGroups": [ // キャッシュするファイルのグループ配列 ...(1)
{ // 1つ目のグループ ...(2)
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/*.css",
"/*.js"
]
}
},
(略:2つ目のassetGroup「assets」)
]
}
キャッシュするファイルは(1)のassetGroupsに設定します。assetGroupsは配列で指定でき、デフォルトではHTML/JavaScript/CSSをキャッシュする「app」という名前のグループ(2)と、assetsフォルダーのファイルをキャッシュする「assets」という名前のグループが登録されています。グループごとに、表2のような設定ができます。
| No. | 設定項目 | 役割 |
|---|---|---|
| 1 | name | グループの名前 |
| 2 | installMode | インストール時のファイル取得モード |
| 3 | updateMode | アップデート時のファイル取得モード |
| 4 | resources | キャッシュするファイル |
installMode、updateModeは、「prefetch」を指定すると、インストール/アップデート直後にすべてのファイルを取得するようになり、「lazy」では、インストール/アップデート直後にはファイルを取得せず、リクエストを受けてから取得するようになります。そのほか設定項目の詳細は公式ページを参照してください。
まとめ
本記事では、ネイティブアプリのようなWebページを実現するProgressive Web Apps(PWA)に対応するAngularの機能を説明しました。Angular CLIのコマンドで、アプリ名やアイコンを定義するWeb App Manifestと、キャッシュ機能を実現するService Workerを、AngularのWebページに自動的に追加できます。
Service Workerを利用すると、Webページにリモートから通知を送り込む、いわゆるプッシュ通知が実現できます。次回記事では、AngularのWebページでプッシュ通知を利用する方法を説明します。
