web-dev-qa-db-fra.com

Angular est dans SAFE_MODE

J'ai un Angular PWA. Son technicien de service fonctionnait parfaitement jusqu'à ce que je passe de Angular 5.0 à 7.2

Après la mise à niveau, je vois l'erreur suivante dans /ngsw/state

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

Arrière-plan de l'application

  • La version angulaire est 7.2.0
  • La version de Service Worker est 7.2.0
  • Je vérifie manuellement les mises à jour à l'aide du service SwUpdate.

Code pour vérifier les mises à jour

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()
      );
    }

Mes étapes de recherche et de dépannage jusqu'à présent:

Dans Chrome

  • Le technicien est enregistré sans aucune erreur
  • J'ai regardé dans l'onglet réseau et j'ai trouvé que le technicien ne téléchargeait jamais 'ngsw.json'. J'ai vu "ngsw.json" être téléchargé lorsque l'application était en Angular 5.0

Screenshot1

  • Je vois que le même problème a été signalé ici . Je ne vois aucune solution appropriée ici.
  • J'ai essayé de sélectionner "Mettre à jour au rechargement", ce qui résout temporairement le problème. La même erreur réapparaît après l'avoir désélectionnée.

Screenshot2

Dans Microsoft Edge

  • Étonnamment, tout fonctionne dans Edge après la mise à niveau.

Mes pensées et mes attentes

  • Étant donné que l'application fonctionne correctement dans MS Edge, je doute qu'il y ait un problème avec la configuration du service worker ou avec la façon dont j'interroge les mises à jour
  • Mon attente est de voir l'état du lecteur comme Normal dans/ngsw/state
34
shobhit vaish

Mettre à jour

Cela sera corrigé à partir de la version 8.2.14 de Angular. Les solutions de contournement ci-dessous ne sont nécessaires qu'avec les anciennes versions.


Anciennes solutions pour <8.2.14

Il semble que ce soit un bug bien connu dans le service worker Angular et que nous pouvons nous attendre à un patch/une version fonctionnelle à un moment donné. La plupart des informations se trouvent dans numéro 25611 comme shobhit vaish déjà indiqué.

Cependant, si vous cherchez une solution maintenant ou si vous allez vous en tenir à une ancienne version Angular 7/8 plus longue, qui ne sera peut-être pas corrigée bientôt, j'essaierai de résumer les solutions de contournement actuellement connues . (Ils peuvent également ne pas être qualifiés de "solution appropriée" ...)

Patcher ngsw-worker.js

Vous pouvez patcher votre fichier ngsw-worker.js Soit après votre ng run app:build:production Où il résidera généralement dans le dossier www à l'intérieur de votre projet (si vous n'avez pas modifié le Angular outputPath). Ou vous pouvez le patcher avant votre build dans node_modules/@angular/service-worker.

Selon la fréquence à laquelle vous créez votre application, vous pouvez le faire simplement manuellement (c'est-à-dire avec un éditeur de texte de votre choix) ou écrire un script par exemple à l'aide de sed .

Vous avez maintenant deux options:

1. Patcher handleMessage()

Rechercher

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

Et remplacez-le par

        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)}`;
                }

En fonction de votre version @angular/service-worker, La signature de handleMessage() peut vous sembler différente et vous pourriez écrire un catch plus sophistiqué, mais avec un peu de chance/probablement, il n'atteindra jamais le catch bloque quand même.
Ce correctif est essentiellement ce qui est suggéré dans n commentaire de gkalpak et très probablement le correctif officiel sera également quelque chose comme ça.

2. Patcher initialize()

Rechercher

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

Et remplacez-le par

                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...');

Avec cela, vous vous assurerez que le bloc catch de initialize() s'exécutera réellement et empêchera le technicien de service d'entrer SAFE_MODE. Cependant, cela peut ne pas être aussi fiable que le premier correctif mais peut également fonctionner pour les techniciens de maintenance qui sont déjà dans SAFE_MODE En raison de ce problème. Il a été proposé dans n commentaire de hsta .

Contournement du problème dans votre application Angular

Si vous ne voulez pas jouer avec ngsw-worker.js, Vous pouvez essayer de détecter l'état du technicien en récupérant your-app.domain/ngsw/state À partir de votre application Angular et si elle est dans SAFE_MODE (pourrait être vérifié par exemple avec une simple recherche regex), vous pouvez essayer de le réinitialiser en supprimant tous les éléments de la mémoire cache, puis en désinscrivant le technicien de service. L'idée a été proposée dans n commentaire de mattlewis92 et approuvée comme probablement un hack de travail dans n commentaire de gkalpak .

Travail temporaire autour du problème manuellement

Comme shobhit vaish déjà découvert, vous pouvez également résoudre manuellement le problème. À côté de la possibilité qui est déjà indiquée dans le message d'origine, vous pouvez également le faire dans les outils de développement du navigateur basé sur chrome sous "Application" -> "Effacer le stockage", en sélectionnant "Annuler l'enregistrement des travailleurs du service" et appuyez sur "Effacer les données du site". Évidemment, le problème peut et va probablement revenir sur les futures mises à jour et n'aidera pas beaucoup les utilisateurs normaux. Mais cela peut être pratique si vous, en tant que développeur, souhaitez simplement le résoudre rapidement pour le moment.

1
Jey DWork