web-dev-qa-db-ja.com

AngularサービスワーカーはSAFE_MODEです

Angular PWAを使用しています。Angular 5.0から7.2にアップグレードするまで、そのサービスワーカーは問題なく動作していました。

アップグレード後、/ngsw/stateに次のerrorが表示されます

Driver state: SAFE_MODE (Initialization failed due to error: Invariant violated (initialize): latest hash null has no known
manifest initialize/<@https://{{domain}}.com/ngsw-worker.js:2227:27
fulfilled@https://{{domain}}.com/ngsw-worker.js:1772:52 ) Latest
manifest hash: none Last update check: never

アプリの背景

  • Angularのバージョンは7.2.0です
  • Service Workerのバージョンは7.2.0です
  • SwUpdateサービスを使用して更新を手動で確認しています。

更新を確認するコード

if (this.updates.isEnabled) {
      const appIsStable$ = this.appRef.isStable.pipe(first(isStable => isStable === true));
      const every21600Ms$ = interval(6 * 60 * 60);
      const every21600MsOnceAppIsStable$ = concat(appIsStable$, every21600Ms$);
      // poll the service worker to check for updates
      every21600MsOnceAppIsStable$.subscribe(() =>
        this.updates.checkForUpdate()
      );
    }

これまでの私の調査とトラブルシューティングの手順:

Chromeの場合

  • Service Workerはエラーなしで登録されています
  • ネットワークタブを調べたところ、Service Workerが「ngsw.json」をダウンロードしないことがわかりました。アプリがAngular 5.0のときに、ngsw.jsonがダウンロードされるのを見ました

Screenshot1

  • 同じ問題が報告されているようです こちら 。ここには適切な解決策はありません。
  • 問題を一時的に修正する「リロード時に更新」を選択してみました。選択を解除すると、同じエラーが再び表示されます。

Screenshot2

Microsoft Edgeで

  • 驚くべきことに、アップグレード後はすべてがEdgeで機能します。

私の考えと期待

  • アプリケーションはMS Edgeで正常に動作しているので、Service Workerの設定や、更新をポーリングする方法に問題があるとは思いません
  • 私の期待は、/ ngsw/stateでドライブの状態を通常として表示することです
34
shobhit vaish

更新

これはAngularバージョン8.2.14で修正されます。以下の回避策は、古いバージョンでのみ必要です。


8.2.14未満の古い回避策

これはAngularサービスワーカーのよく知られたバグであり、ある時点でパッチ/作業バージョンを期待しているようです。ほとんどの情報は issue 25611 にあります shobhit vaish はすでに述べたとおりです。

ただし、今すぐに解決策を探している場合、または古いAngular 7/8バージョンを使い続ける予定であり、すぐにパッチが適用されない可能性がある場合は、現在知られている回避策をまとめます。 。 (また、「適切な解決策」と見なされない場合もあります...)

パッチ適用_ngsw-worker.js_

_ngsw-worker.js_ファイルは、_ng run app:build:production_の後にパッチを適用できます。このファイルは通常、プロジェクト内のwwwフォルダーにあります(Angular outputPathを変更していない場合)。または、_node_modules/@angular/service-worker_内でビルドする前にパッチを適用できます。

アプリをビルドする頻度に応じて、手動で(つまり、選択したテキストエディターを使用して)、または sed を使用してスクリプトを記述できます。

現在、2つのオプションがあります。

1.パッチhandleMessage()

検索する

_        handleMessage(msg, from) {
            return __awaiter$5(this, void 0, void 0, function* () {
_

そしてそれを

_        handleMessage(msg, from) {
            return __awaiter$5(this, void 0, void 0, function* () {
                if (this.initialized === null) {
                    this.initialized = this.initialize();
                }
                try {
                    yield this.initialized;
                }
                catch (e) {
                    this.state = DriverReadyState.SAFE_MODE;
                    this.stateMessage = `Initialization failed due to handleMessage() error: ${errorToString(e)}`;
                }
_

_@angular/service-worker_バージョンによっては、handleMessage()のシグネチャが異なって見える場合があり、より洗練されたcatchを記述できますが、おそらくcatchブロックに到達しない可能性があります。
このパッチは基本的に gkalpakによるコメント で提案されているものであり、おそらく公式修正もこのようなものになります。

2.パッチinitialize()

検索する

_                try {
                    // Read them from the DB simultaneously.
                    [manifests, assignments, latest] = yield Promise.all([
                        table.read('manifests'),
                        table.read('assignments'),
                        table.read('latest'),
                    ]);
_

そしてそれを

_                try {
                    // Read them from the DB simultaneously.
                    [manifests, assignments, latest] = yield Promise.all([
                        table.read('manifests'),
                        table.read('assignments'),
                        table.read('latest'),
                    ]);
                    if (latest.latest === null) throw new Error('Error latest.latest is null for what ever reason...');
_

これにより、initialize()catchブロックが実際に実行され、Service Workerが_SAFE_MODE_に入るのを防ぐことができます。ただし、これは最初のパッチほど信頼性が高くない可能性がありますが、この問題のためにすでに_SAFE_MODE_にあるService Workerでも機能する可能性があります。 hstaによるコメント で提案されました。

Angularアプリで問題を回避する

_ngsw-worker.js_をいじりたくない場合は、Angularアプリ内から_your-app.domain/ngsw/state_をフェッチして、サービスワーカーの状態を検出してみてください。 _SAFE_MODE_(たとえば、単純なregex検索で確認できます)キャッシュストレージからすべてのアイテムを削除し、Service Workerの登録を解除することで、リセットすることができます。これに対するアイデアは mattlewis92によるコメント で提案され、おそらく gkalpakによるコメント でハッキングの作業として承認されました。

一時的に問題を手動で回避する

shobhit vaish はすでに判明しているため、手動で問題を解決することもできます。元の投稿ですでに述べられている可能性の横にあるchromeベースのブラウザーの開発ツールでもこれを行うことができます。[アプリケーション]-> [ストレージのクリア]で、[サービスワーカーの登録解除]を選択してヒットします。 「クリアサイトデータ」。明らかに問題は将来のアップデートで再発する可能性があり、おそらく再発するでしょう。通常のユーザーにとってはあまり役に立ちません。ただし、開発者が現時点で迅速に解決したい場合は便利です。

1
Jey DWork