Angular PWA

October 30, 2019 Angular 2 minutes, 57 secondes

Angular PWA et firabse.

Pour débuter, j'ai commencé par un starter kit Angular PWA comme par exemple :

https://github.com/Moelgaard85/angular-starter-pwa

Sinon il suffit de créer un projet Angular 6 et d'executer la commande suivante:

ng add @angular/pwa --project project_name

PS: Pas encore tester une migration sur Angular 7

Le contenu de l'article suivant retrace les problématiques et ajustements que j'ai réalisés pour avoir une PWA.

index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>ScalPwa</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="msapplication-starturl" content="/">
  <meta name="theme-color" content="#f48c5b">
  <meta name="description" content="Share things happening around you which you dislike"/>

  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="manifest" href="manifest.json">

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" integrity="sha384-Zug+QiDoJOrZ5t4lssLdxGhVrurbmBWopoEl+M6BdEfwnCJZtKxi1KgxUyJq13dy" crossorigin="anonymous">

  <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/js/bootstrap.min.js" integrity="sha384-a5N7Y/aK3qNeh15eJKGWxsqtnX/wWdSZSKp+81YjTmS15nvnvxKHuzaWwXHDli+4" crossorigin="anonymous"></script>

</head>
<body>
  <noscript>
    <h3 style="color: #673ab7; font-family: Helvetica; margin: 2rem;">
        Sorry, but app is not available without javascript
    </h3>
  </noscript>
  <app-root></app-root>
</body>
</html>
  • Ne pas oublier les meta tag
  • Ne pas oublier de référencer le manifest.json
  • Ne pas oublier le block "noscript"

Main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from 'app/app.module';
import { environment } from 'environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .then(() => {
    console.log('START SW REGISTER');
    if ('serviceWorker' in navigator) {
      console.log('SW REGISTER REQUESTED');
      navigator.serviceWorker.register('./ngsw-worker.js') ;
      console.log('SW REGISTER FINISHED');
    }
  })
  .catch(err => console.log('ERROR SW REGISTRATION' + err));
  • Ne pas oublier la déclaration du service worker

manifest.json

Mon fichier manifest.json se trouve au même niveau que mon package.json, et j'utilise un script pour le copier dans le repertoire du Build comme décrit plus tard (cpx manifest.json dist/)

Voici mon fichier manifest.json pour mon application :

{
  "short_name": "ScalPwa",
  "name": "ScalPwa",
  "theme_color": "#f48c5b",
  "background_color": "#ffffff",
  "display": "standalone",
  "orientation": "portrait",
  "scope": "/",
  "start_url": "/",
  "icons": [
    {
      "src":"/assets/favicons/apple-touch-icon.png",
      "type":"image/png"
    },
    {
      "src":"/assets/favicons/favicon-16x16.png",
      "sizes":"16x16",
      "type":"image/png"
    },
    {
      "src":"/assets/favicons/favicon-32x32.png",
      "sizes":"32x32",
      "type":"image/png"
    },
    {
      "src":"/assets/favicons/favicon-96x96.png",
      "sizes":"96x96",
      "type":"image/png"
    },
    {
      "src":"/assets/favicons/favicon-196x196.png",
      "sizes":"196x196",
      "type":"image/png"
    },
    {
      "src":"/assets/favicons/mstile-70x70.png",
      "sizes":"70x70",
      "type":"image/png"
    },
    {
      "src":"/assets/favicons/mstile-144x144.png",
      "sizes":"144x144",
      "type":"image/png"
    },
    {
      "src":"/assets/favicons/mstile-150x150.png",
      "sizes":"150x150",
      "type":"image/png"
    },
    {
      "src":"/assets/favicons/mstile-310x310.png",
      "sizes":"310x310",
      "type":"image/png"
    },
    {
      "src":"/assets/images/icons/android-chrome-192x192.png",
      "sizes":"192x912",
      "type":"image/png"
    },
    {
      "src":"/assets/images/icons/android-chrome-512x512.png",
      "sizes":"512x512",
      "type":"image/png"
    }

  ]
}

Icons

Ne pas oublier de générer des icones pour la déclaration dans le manifest. J'utilise le site : https://realfavicongenerator.net/

Scripts de déploiement

Dans le fichier package.json, voici les scripts utiles pour le déploiement :

"ngsw-config": "node_modules/.bin/ngsw-config dist ngsw-config.json",
"ngsw-copy": "cpx node_modules/@angular/service-worker/ngsw-worker.js dist/",
"manifest-copy": "cpx manifest.json dist/",
"deployprod": "ng build --prod && npm run ngsw-config && npm run ngsw-copy && npm run manifest-copy && firebase deploy"

Déploiement sur Firebase

Initialiser pour le projet Firebase :

  • npm install -g firebase-tools
  • firebase login => authentification à firebase
  • firebase init => initialisation dans le projet des besoins Firebase
  • firebase use --add => pour associer votre projet à un projet firebase
  • firebase deploy => déploiement de votre solution dans Firebase

Pour que firebase deploy, il faut avoir générer votre projet pour un déploiement (ng build --prod). Vérifier que le fichier firebase.json pointe bien vers votre répertoire de build (dist par défaut pour moi) :

{
  "hosting": {
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  },
  "database": {
    "rules": "database.rules.json"
  }
}

Si vous rencontrez le message d'erreur suivant : "firebase deploy error Authorization failed"

Executer la commande : firebase login --reauth

Afin d'optimiser mon déploiement j'ai créé des scripts (comme décrit précédemment) et je peux donc déployer tout en une seule commande : npm run deployprod.

Vérifier votre PWA

Ouvrir l'application dans un onglet sous Chrome et appuyer sur F12 (outil de dev).

Dans l'onglet Audit, lancer un outil pour vérifier la compatibilité PWA.

alt