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
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
Dans Microsoft Edge
Mes pensées et mes attentes
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.
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" ...)
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:
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.
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 .
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 .
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.