web-dev-qa-db-ja.com

Angular 6 Service Workerの鮮度によるアセットのキャッシュ

Angular Service Workerを既存のプロジェクトに統合しようとしています。正しく理解できた場合、データがAngular SWにキャッシュされる方法は2つあります。資産データをプリフェッチまたは遅延更新し、特定のAPI呼び出しやその他のXHRリクエストをキャッシュすることができます。

私が達成しようとしているのは、ネットワークを介して特定のアセットを最初にロードすることです。リクエストがタイムアウトになるか、アクセスできない場合、キャッシュを介して処理されます。 API呼び出しをキャッシュするときのfreshness戦略と同じです。しかし、AngularプロジェクトでアセットとしてロードされるJSファイルに対して、このようなフレッシュネスロードメカニズムを設定する方法はないようです。テスト用のサンプルプロジェクトをセットアップしました:- https://github.com/philipp-schaerer-lambdait/angular-service-worker-test

次の例は標準のAngular Appであり、作業中の実際のプロジェクトは含まれていませんが、キャッシュしたい要素を示しています。構造は次のようになります。

\_ Angular root  
 |_ src/
   |_ index.html <----------- links to excluded_asset.js
   |_ app/
   |_ assets/
     |_ excluded_asset.js <-- this one is excluded in ngsw-config.json
     |_ included_asset.js
     |_ ...

ここで関連する構成:

ngsw-config.json

{
    "index": "/index.html",
    "assetGroups": [
        {
            "name": "app",
            "installMode": "prefetch",
            "resources": {
                "files": ["/favicon.ico", "/index.html", "/*.css", "/*.js"]
            }
        },
        {
            "name": "assets",
            "installMode": "lazy",
            "updateMode": "prefetch",
            "resources": {
                "files": ["/assets/**", "!/assets/excluded_asset.js"]
            }
        }
    ]
}

アセットにfreshnessinstallModeを使用して、updateMode戦略のようなキャッシュ動作を実現することは可能ですか?

アセットキャッシュから除外しようとしましたが、ネットワーク経由でロードされましたが、オフラインになった後は明らかにサービスワーカーによって配信されません。

その後、dataGroupsを介して再度追加しようとし、戦略をfreshnessに設定しましたが、アセット構成から除外されると、アセットは再度キャッシュされないようです。また、このファイルにdataGroups設定を使用できるとは思わない。

"dataGroups": [
    {
        "name": "config",
        "urls": ["assets/excluded_asset.js"],
        "cacheConfig": {
            "maxSize": 10,
            "maxAge": "1d",
            "timeout": "100",
            "strategy": "freshness"
        }
    }
}

何かを見逃したか、freshness戦略でアセットをキャッシュする方法はありませんか?ファイルを移動しないか、ファイルの要求方法を変更することをお勧めします。

編集

キャッシュされたアセットディレクトリの外に移動してdataGroups設定に含めようとしましたが、動作しませんでした。

15
Reizouko

サービスワーカーを使用した新しいアプリ

コマンドは次のようになります。

ng new myApp --service-worker (or using the alias — -sw )

このサービスワーカーフラグを使用すると、Angular CLI 1.6が自動化を行います。

  1. Angular Service Workerパッケージがインストールされます。
  2. NGSWのビルドサポートが有効になります。
  3. NGSWがアプリケーションに登録されます。
  4. NGSW構成ファイルは、いくつかのスマートなデフォルトで作成されます。

とにかく、CLI 1.6がリリースされた後でも、NGSWサポートを既存のアプリに追加するには手動で実行する必要があるため、これらの手順を再現する方法を知っておくとよいでしょう。 Angular Service WorkerをPWAtterに追加しましょう。

Angular Service Workerを既存のアプリに追加する

上記と同じ4つの手順を手動で実行してみましょう。

1。 NGSWのインストール

npm install @angular/service-worker --save

2。ビルドサポートを有効にします(Angular CLI 1.6のみ、以下の通知を参照してください)

ng set apps.0.serviceWorker=true

または、.angular-cli.jsonファイルでこのパラメーターを手動で追加/編集します。

重要!とりあえず、Angular CLI 1.5を使用する場合は、.angular-cli.jsonにこのプロパティがないことを確認してください。ビルドエラーが発生します。このステップをエミュレートする方法については、以下のAngular CLI 1.5をご覧ください。

3。 AppModuleにNGSWを登録します。これは、Angular CLI 1.6での表示方法です。

import { ServiceWorkerModule } from '@angular/service-worker'
import { environment } from '../environments/environment';

...

@NgModule({
  imports: [
    ...
    environment.production ? ServiceWorkerModule.register('/ngsw-worker.js') : []
  ],
  ...
})
export class AppModule { }

4。 NGSW構成ファイルを作成します(デフォルト名はsrc/ngsw-config.jsonです)。デフォルトのコンテンツはAngular CLI 1.6によって生成されます。

{
  "index": "/index.html",
  "assetGroups": [{
    "name": "app",
    "installMode": "prefetch",
    "resources": {
      "files": [
        "/favicon.ico",
        "/index.html"
      ],
      "versionedFiles": [
        "/*.bundle.css",
        "/*.bundle.js",
        "/*.chunk.js"
      ]
    }
  }, {
    "name": "assets",
    "installMode": "lazy",
    "updateMode": "prefetch",
    "resources": {
      "files": [
        "/assets/**"
      ]
    }
  }]
}

現時点では、Angular CLI 1.5を使用している間、ステップ2からビルドサポートをエミュレートする必要があります。実際には、ng build --prodコマンドに加えて、2つの追加アクションを実行する必要があります。 NGSWを使用するには!):

NGSW CLI ngsw-configを使用して、NGSW構成ファイルsrc/ngsw-config.jsonに基づいてNGSW制御(マニフェスト)ファイルngsw.jsonを生成します。

NGPM自体をnpm_modulesパッケージフォルダーからdistフォルダーにコピーします。

NGSWサポートを使用して実稼働ビルドを生成する簡単なコマンドを1つ作成するには、npmスクリプトを追加します。

{
  ...
  "scripts": {
    ...
    "ngsw-config": "node_modules/.bin/ngsw-config dist src/ngsw-config.json",
    "ngsw-copy": "cp node_modules/@angular/service-worker/ngsw-worker.js dist/",
    "build-prod-ngsw": "ng build --prod && npm run ngsw-config && npm run ngsw-copy",
    "serve-prod-ngsw": "npm run build-prod-ngsw && http-server dist -p 8080"
  }
}

ここでnpm run build-prod-ngswを実行すると、Angular PWAがdistフォルダーに格納されます。オプションで、http-serverを実行することにより、最も簡単なnpm run serve-prod-ngswを使用してサービスを提供できます。

重要! ng serveを使用してAngular Service Workerをテストしないでください。この開発サーバーは、PWAフローと連携して動作するようには設計されていません。アプリの製品版を常にビルドし、静的Webサーバーを使用して配布フォルダーから提供します。

アプリケーションシェル

上記のアクションを実行してnpm run build-prod-ngswを実行すると、デフォルトのAngular PWAの準備が整います。アプリケーションをデプロイするか、静的Webサーバーを使用してローカルで実行します(私の場合はhttp-serverパッケージ、ビルドして提供するにはnpm run serve-prod-ngswを実行します)。

オフラインになった後、アプリケーションは動作します。どうして? NGSWは、構成ファイルのassetGroupsセクションにリストされているすべてのリソースをキャッシュしたため、現在はレコードでいっぱいのキャッシュストレージからリソースを提供する責任があります。

enter image description here

Service Workerは登録済みでアクティブです

enter image description here

キャッシュされた応答のコンテンツを表示できます(現時点でChrome Canaryでのみ使用可能)

NGSWは、キャッシュストレージを使用して、HTTP応答データと一部のメタデータの両方を保存し、バージョン管理を処理します。

enter image description here

NGSWによるストレージのタイプ

  • 接尾辞が:cacheのエントリ—実際のHTTP応答。
  • 接尾辞:metaが付いたエントリ—バージョン管理メタ情報を保存します。後でこの種類の保存データはindexedDBに移動される可能性があります。

DevToolsを開いたままにしておくと、キャッシュワーカーセクション内のエントリは、おそらくサービスワーカー側からの各アクションの後に自動的に更新されません。実際のデータを表示する場合は、右クリックして[キャッシュの更新]を選択します。

右。 NGSW構成ファイルのデフォルト形式では、マテリアルアイコンwebfontを使用しているため、このケースでは不十分です。明らかに、これらのリソース(対応するCSSおよびWOFF2ファイル)はNGSWによってキャッシュされませんでしたが、デフォルトのassetGroupsおよびappに加えてassetsにもう1つのグループを追加することで簡単に修正できます。それをfontsと呼びましょう:

{
  ...
  "assetGroups": [
   ...
   {
    "name": "fonts",
    "resources": {
      "urls": [
        "https://fonts.googleapis.com/**",
        "https://fonts.gstatic.com/**"
      ]
    }
  }]
}

フォントファイルの正確なURLはウェブフォントのバージョン管理をサポートするために随時変更される可能性があるため、globs構文を使用してこれらのリソースを指定することは理にかなっています。また、installModeupdateModeも指定していないことに気付くかもしれません。一方で、これはデフォルト値であるため、結果のNGSW制御ファイルでは両方がprefetchとして設定されます。一方、urls- wayの詳細はリソースをリストするため、リクエストされた後にのみキャッシュされます。

再構築して実行し、オフラインモードに切り替えた後、すべてのアイコンが配置されたアプリケーションの通常の状態が表示されます。

キャッシュストレージに2つの新しいエントリが表示されます。

enter image description here

NGSWによって生成されたストレージ

キャッシュされたフォントをプレビューすることもできます。

enter image description here

assetGroupsdataGroupsには根本的な違いがあります。

  • assetGroupsは、アプリの[シェル]バージョンを追跡しています。
  • dataGroupsはアプリのバージョンに依存しません。それらは独自のキャッシュポリシーを使用してキャッシュされ、APIレスポンスを処理するのに適切なセクションです。

ランタイムキャッシング

/timeline APIエンドポイントにNetwork-First戦略を使用し、/favoritesエンドポイントにCache-First戦略を使用します。 src/ngsw-config.jsonの対応するセットアップは次のようになります。

{
  ...
  "dataGroups": [{
      "name": "api-freshness",
      "urls": [
        "/timeline"
      ],
      "cacheConfig": {
        "strategy": "freshness",
        "maxSize": 100,
        "maxAge": "3d",
        "timeout": "10s"
      }
    },
    {
      "name": "api-performance",
      "urls": [
        "/favorites"
      ],
      "cacheConfig": {
        "strategy": "performance",
        "maxSize": 100,
        "maxAge": "3d"
      }
    }
  ]
}

NGSWの動作を定義するメインスイッチがあります:cacheConfig / strategy。ネットワーク優先戦略の場合、freshness、キャッシュ優先-の場合— performance

APIレスポンスを取得してキャッシュし、オフラインに切り替えるには、ビルド、提供、タイムラインのロードボタン、お気に入りのロードボタンの順にクリックします。

オンラインモードの最適化について。オンラインに戻り、Timeline / Favoritesを1回または2回クリックします。ネットワークトリップ全体をスキップしてキャッシュからデータを取得したからといって、お気に入りがすぐに読み込まれることは明らかです。キャッシュする期間を指定するにはcacheConfigセクションの設定を使用して—詳細な制御があります。

NGSWは、いくつかの非常にスマートなネットワーク最適化で私たちを大いに助けてくれました。

5
Kousic

私も同じ問題を抱えています。私が見つけた解決策は、常に最新のjsファイルとcssファイルを持っていることが、キャッシュされたアセットからindex.htmlを除外することです。

{
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "updateMode": "prefetch",
      "resources": {
        "files": [
          "/*.css",
          "/*.js",
          "!/index.html" // Right here!!!!!
        ]
      }
    },
    {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "lazy",
      "resources": {
        "files": ["/static/**"]
      }
    }
  ]
}

"outputHashing": "all", to angular= build configuration。コードを変更すると、別の名前のファイルが生成されます。スクリプトタグ(またはリンクタグ)が自動的に追加されます)htmlファイル(サービスワーカーは無視します)に変更をプロダクションにプッシュすると、index.htmlは新しいjsファイルとcssファイルを指します。

もちろん、これは非常に明白な方法です。index.htmlはサービスワーカーによってキャッシュされませんが、少なくともユーザーに最新のファイルをまっすぐに提供することができます。

アセットにも「鮮度」オプションがある方法があればいいのにと思いました...

2
Etienne Talbot