web-dev-qa-db-fra.com

Activer le cache via la fraîcheur dans Angular 6 Service Worker

J'essaie d'intégrer le Angular Service Worker dans un projet existant. Si je l'ai bien compris, il y a deux cas où les données sont mises en cache dans Angular SW. Il est possible de pré-extraire ou de mettre à jour les données de l'actif et de mettre en cache des appels d'API spécifiques et d'autres demandes XHR.

Ce que j'essaie de réaliser, c'est de charger d'abord un actif spécifique via le réseau, si la demande arrive à expiration ou n'est pas accessible, elle sera servie via le cache. Tout comme la stratégie freshness lors de la mise en cache des appels d'API. Mais il semble qu'il n'y ait aucun moyen possible de configurer un tel mécanisme de chargement de fraîcheur pour un fichier JS qui est chargé en tant qu'actif dans le projet Angular. J'ai configuré un exemple de projet pour tester: - https://github.com/philipp-schaerer-lambdait/angular-service-worker-test

L'exemple suivant est une application Angular Angular et ne contient pas le projet réel avec lequel je travaille mais montre les éléments que je voudrais mettre en cache, la structure ressemble à ceci:

\_ 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
     |_ ...

Voici les configurations pertinentes:

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"]
            }
        }
    ]
}

Est-il possible d'obtenir un comportement de mise en cache comme la stratégie freshness en utilisant les installMode et updateMode pour les actifs?

J'ai essayé de l'exclure du cache d'actifs et il a été chargé via le réseau, mais ne sera évidemment pas livré par le technicien après s'être déconnecté.

Après cela, j'ai essayé de l'inclure à nouveau via dataGroups et de définir la stratégie sur freshness mais il semble que l'actif ne sera plus mis en cache une fois qu'il sera exclu de la configuration de l'actif. Je ne pense pas non plus que les paramètres dataGroups puissent être utilisés pour ce fichier.

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

Ai-je raté quelque chose ou n'y a-t-il aucun moyen de mettre en cache un actif via la stratégie freshness? Il serait préférable de ne pas déplacer le fichier ou de modifier la façon dont le fichier est demandé.

MODIFIER

J'ai essayé de le déplacer en dehors des répertoires d'actifs mis en cache et de l'inclure avec le paramètre dataGroups, cela n'a pas fonctionné non plus.

15
Reizouko

Nouvelle application avec le technicien de service

La commande sera la suivante:

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

Ayant cet indicateur de travailleur de service, Angular CLI 1.6 fera une certaine automatisation pour nous:

  1. Le package Angular Service Worker sera installé.
  2. Le support de build pour NGSW sera activé.
  3. NGSW sera enregistré pour votre candidature.
  4. Le fichier de configuration NGSW sera créé avec quelques valeurs par défaut intelligentes.

Quoi qu'il en soit, même après la sortie de CLI 1.6, il est bon de savoir comment reproduire ces étapes, car nous devons les exécuter manuellement pour ajouter la prise en charge NGSW à l'application existante. Allons ajouter Angular Service Worker à PWAtter.

Ajout de Angular Service Worker à l'application existante

Exécutons manuellement les 4 mêmes étapes ci-dessus:

1. Installer NGSW

npm install @angular/service-worker --save

2. Activer le support de build (uniquement pour Angular CLI 1.6, voir la remarque ci-dessous)

ng set apps.0.serviceWorker=true

ou ajoutez/modifiez manuellement ce paramètre dans .angular-cli.json fichier.

Important! Pour le moment, lorsque nous utilisons Angular CLI 1.5, veuillez vous assurer que vous n'avez pas cette propriété dans .angular-cli.json, cela entraînera des erreurs de construction. Découvrez comment émuler cette étape dans Angular CLI 1.5 ci-dessous).

3. Enregistrez NGSW dans votre AppModule. Voici à quoi cela ressemblera dans 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. Créez le fichier de configuration NGSW (le nom par défaut est src/ngsw-config.json). Voici le contenu par défaut qui sera généré par 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/**"
      ]
    }
  }]
}

Pour le moment, lors de l'utilisation de Angular CLI 1.5, nous devons également émuler le support de génération à partir de l'étape 2. En fait, il y a 2 actions supplémentaires à effectuer en plus de ng build --prod commande (il est important d'utiliser la génération de production pour utiliser NGSW!):

Générez le fichier de contrôle (manifeste) NGSW ngsw.json basé sur le fichier de configuration NGSW src/ngsw-config.json à l'aide de la CLI NGSW ngsw-config CLI.

Copiez NGSW lui-même du dossier du package npm_modules vers notre dossier dist.

Pour avoir une commande simple pour générer une génération de production avec le support NGSW, ajoutons quelques scripts 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"
  }
}

Maintenant, si nous exécutons npm run build-prod-ngsw nous aurons Angular PWA dans le dossier dist. Eventuellement, nous pourrions le servir en utilisant le plus simple http-server en exécutant npm run serve-prod-ngsw.

Important! Ne pas utiliser ng serve pour tester votre Angular Service Worker. Ce serveur de développement n'a pas été conçu pour fonctionner en collaboration avec le flux PWA. Créez toujours une version de production de l'application et servez-la à partir de votre dossier de distribution en utilisant n'importe quel statique serveur Web.

Shell d'application

Si nous effectuons les actions ci-dessus et exécutons npm run build-prod-ngsw - le Angular angulaire dans sa forme par défaut est prêt pour nous! Déployez l'application ou exécutez-la simplement localement en utilisant n'importe quel serveur Web statique (http-server package dans mon cas, vous exécutez npm run serve-prod-ngsw pour construire et servir).

L'application fonctionnera après notre mise hors ligne. Pourquoi? Parce que NGSW a mis en cache toutes les ressources répertoriées dans la section setGroups du fichier de configuration, et qu'il est maintenant responsable de les servir à partir du stockage de cache, qui regorge désormais d'enregistrements:

enter image description here

Le technicien de service est enregistré et actif

enter image description here

Nous pouvons afficher le contenu de la réponse en cache (disponible uniquement dans Chrome Canary pour le moment)

NGSW utilise Cache Storage pour stocker à la fois les données des réponses HTTP et certaines métadonnées pour gérer le contrôle de version:

enter image description here

Types de stockages par NGSW

  • Entrées avec suffixe :cache - réponses HTTP réelles.
  • Entrées avec suffixe :meta - pour stocker les méta-informations de version. Plus tard, ce type de données stockées pourrait être déplacé vers indexedDB.

Si vous gardez DevTools ouvert, les entrées dans la section Cache Storage ne seront probablement pas mises à jour automatiquement après chaque action du côté du technicien de service. Si vous souhaitez voir les données réelles, cliquez avec le bouton droit et choisissez Actualiser les caches.

Droite. La forme par défaut du fichier de configuration NGSW ne suffit pas dans notre cas car nous utilisons la police Web Material Icons. Évidemment, ces ressources (fichiers CSS et WOFF2 correspondants) n'ont pas été mises en cache par NGSW, mais nous pouvons facilement le corriger en ajoutant un groupe de plus à assetGroups en plus des paramètres par défaut app et assets ceux. Appelons cela fonts:

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

Il est logique de spécifier ces ressources à l'aide de la syntaxe globs car l'URL exacte du fichier de police peut changer de temps en temps pour prendre en charge le contrôle de version de la police Web. Vous pouvez également remarquer que nous n'avons spécifié ni installMode ni updateMode. D'une part, les deux seront définis comme prefetch dans le fichier de contrôle NGSW résultant car il s'agit d'une valeur par défaut. Par contre, ils ne seront mis en cache qu'après avoir été demandés car les spécificités de urls- permettent de lister les ressources.

Après avoir reconstruit, exécuté et basculé en mode hors ligne, nous verrons l'état normal de l'application avec toutes les icônes à la place.

Dans le cache de stockage, nous verrons deux nouvelles entrées:

enter image description here

Stockages générés par NGSW

Nous pouvons même prévisualiser la police mise en cache:

enter image description here

Il existe une différence fondamentale entre assetGroups et dataGroups.

  • assetGroups suit la version de l'application [Shell].
  • dataGroups sont indépendants de la version de l'application. Ils sont mis en cache à l'aide de leurs propres politiques de cache, et c'est la section appropriée pour gérer nos réponses API.

Mise en cache d'exécution

Pour utiliser la stratégie Network-First pour mon /timeline Point de terminaison API et stratégie Cache-First pour le /favorites point final. La configuration correspondante dans src/ngsw-config.json ressemblera:

{
  ...
  "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"
      }
    }
  ]
}

Un interrupteur principal définit le comportement de NGSW: cacheConfig / strategy. Pour la stratégie réseau d'abord, c'est freshness, pour cache-first - performance.

Maintenant, créez, diffusez, cliquez sur Charger mes boutons de chronologie et Charger mes favoris pour obtenir et mettre en cache les réponses de l'API et basculer en mode hors connexion.

À propos de l'optimisation pour le mode en ligne. Revenez en ligne et cliquez sur Timeline / Favorites une ou deux fois. Il est clairement visible que les favoris sont chargés immédiatement, simplement parce que nous ignorons tout le trajet réseau et obtenons les données du cache. Pour spécifier la durée de mise en cache En utilisant les paramètres dans la section cacheConfig - nous avons le contrôle à grain fin là-bas.

NGSW nous a beaucoup aidés avec des optimisations de réseau vraiment intelligentes, nécessitant seulement une configuration JSON de notre part.

5
Kousic

J'ai eu le même problème. La solution que j'ai trouvée pour toujours avoir des fichiers js et css à jour consiste simplement à exclure le fichier index.html des ressources mises en cache.

{
  "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/**"]
      }
    }
  ]
}

Assurez-vous d'avoir "outputHashing": "all", à votre angular. De cette façon, lorsque vous apportez une modification à votre code, il générera un fichier avec un nom différent. Il ajoutera ensuite automatiquement la balise de script (ou balise de lien) ) dans votre fichier html (que l'ouvrier des services ignorera) et dès que vous poussez vos modifications en production, l'index.html pointera vers vos nouveaux fichiers js et css.

Bien sûr, cela craint d'une manière très évidente: votre index.html ne sera pas mis en cache par le service worker, mais au moins cela permettra aux utilisateurs qui reviennent d'avoir directement les fichiers les plus récents.

Je souhaitais vraiment qu'il y ait un moyen d'avoir une option "fraîcheur" pour les actifs aussi ...

2
Etienne Talbot