Les PWA ou applications web progressives, comme on pourrait les traduire, sont des pages web ou des sites qui « ressemblent » aux traditionnelles applications dites « natives » que l’on trouve via les app stores sur son téléphones mobile. Elles sont l'une des priorités de Google pour 2018 et nous vous suggérons de vous y intéresser de près ! Voici dans cet article une présentation des PWA, ainsi qu'un exemple de code utilisé pour le site web Autovisual.com.

Introduction aux PWA alias les Progressive Web Apps

Les applications web progressives comme on pourrait les traduire sont des pages web ou des sites qui « ressemblent » aux traditionnelles applications dites « natives » que l’on trouve via les app stores sur son téléphones mobile. Mozilla définit les Progressive Web Apps (que nous désignerons PWA par la suite) comme des « applications web progressives » faisant office de « bons vieux sites web mais en mieux ».

De gros acteurs sont passés aux PWA, de nombreux exemples de différents marchés sont représentés sur le show case de Google (source : https://developers.google.com/web/showcase/) ou encore sur PWA.rocks. On y retrouve des géants du web, des éditeurs, des jeux ou encore des e-commerçants.

Définition des PWA : Il s’agit de sites web dont on peut partager l’URL et qui sont accessibles sans app store. Les PWA doivent être optimisées pour des situations de mobilité et leurs formats doivent s’adapter aux différents appareils et supports.

Elles doivent aussi avoir la même expérience utilisateur qu’aurait un mobinaute avec l’icône de l’application disponible sur l’écran d’accueil, des notifications, un affichage en full screen.

Les 8 fonctionnalités préconisées par le support Google

Les PWA doivent répondre à plusieurs critères. Elles doivent être :

  • Progressives : elles fonctionnent quel que soit le choix de navigateur web. C’est la différence majeure avec les applications natives ou hybrides. Il s'agit donc de permettre une expérience toujours la meilleure, peu importe le navigateur, sans décliner l’expérience tout en dispensant les avantages du mobile.
  • Re-engageables : elles fidélisent et permettent aux utilisateurs d’être impliqués avec l’application même quand les appareils sont inactifs.
  • Adaptatives : elles conviennent à de nombreux formats : bureau, smartphone, tablette, etc.
  • Découvrables : on peut les reconnaître en tant qu’application et elles être référencées par les moteurs de recherche.
  • Installables : elles sont disponibles sur l'appareil, et notamment sur l'écran d'accueil sans avoir recours aux app stores (ou autre boutique pour installer une application).
  • Partageables : on peut les partager via une URL, sans installation complexe.
  • Indépendantes du réseau : elles sont maintenues disponibles hors-ligne ou sur un réseau de faible qualité.
  • Sécurisées : elles sont protégées contre l'espionnage et contre la falsification du contenu (HTTPS).

Source : https://developers.google.com/web/progressive-web-apps/

Budget pour développer et maintenir une PWA

En face du coût conséquent pour développer une application native, on se retrouve souvent avec l’argument d’un temps passé plus long. Cependant, le marché des applications natives (apps) demeure saturé en 2017. Les utilisateurs installent beaucoup d’applications mais finissent par se servir toujours du même top 10. Les PWA sont présentées par Google comme une alternative.

Une Progressive Web App est censée a priori limiter les coûts de maintenance, car on ne devrait pas avoir besoin de faire un développement spécifique pour chaque système d’exploitation mobile (Android, iOS, Windows mobile). A noter que comme il s’agit d’une nouvelle technologie introduite en 2016, tous les navigateurs ne supportent pas les PWA au départ.

Le mobile : un enjeu pour les géants du web

Lors de son événement Chrome Dev Summit très axé PWA fin 2017, Google a montré clairement sa priorité pour une adoption en 2018. D’ailleurs depuis cette période, Microsoft, Apple et Mozilla planifient les fonctionnalités nécessaires dans leurs navigateurs pour entrer dans la danse.
Les PWA vont d'ailleurs de pair avec les enjeux de Google au niveau du mobile : des performances toujours plus accrues et une expérience utilisateur au top !

Installation d’une PWA

En situation de mobilité, répondre aux besoins de ses utilisateurs ne va plus forcément passer par les applications natives. Leur contenu n’est pas forcément à jour et l’installation d’une application est souvent interrompue faute de réseau suffisant. Cela engendre de la frustration et de la perte de temps. On peut ranger les applications hybrides dans le même panier que les applications natives en la matière.

Installer une PWA est donc le compromis entre les applications natives et les sites mobiles mais uniquement avec leurs avantages :

  • Aspect d’une application mobile ;
  • Ouverture rapide de l’app via une icône sur l’écran d’accueil ;
  • Mise à disposition des contenus et services hors ligne (hors réseau, mode avion) ;
  • Synchronisation des contenus et des conflits lors de la prochaine mise à disposition du réseau ;
  • Accès aux ressources partagées du système comme le système de localisation, le répertoire, l’appareil photo etc. ;
  • Installation transparente des mises à jour hors app stores.

Une installation minimale est cependant requise sur l’appareil afin de pouvoir fonctionner comme une app mobile.

Accéder aux données même hors ligne

Les PWA utilisent les Services Workers des navigateurs pour fonctionner sans connexion. Les Service Workers sont des petits scripts tels des proxies qui font le pont entre le client, le cache du navigateur et le serveur. Les données mises en cache permettent l’accès aux informations des données stockées en mode hors connexion.
Ces scripts évoluent en permanence avec l’amélioration et l’évolution des navigateurs.

Etude de cas : Autovisual.com

Les PWA ou Progressive Web App sont l'une des priorités de Google en ce début 2018. Voici comment le site Autovisual.com est passé en mode offline grâce à la ressource Workbox, mise en service par Google. Cette ressource permet de ne pas avoir à recoder tout depuis le début. Le développeur d’Autovisual.com (Laurent Debricon) partage ici avec nous son expérience des Progressive Web App qu’il a gérées en choisissant les données qu’il avait à afficher en mode offline ou non. Une bonne gestion du cache dont il partage des extraits de code avec les lecteurs d'Abondance. Merci à lui !

AutoVisual (voir figure 1) est un comparateur de prix et visualisateur du marché automobile.


Fig. 1. Exemple de visualisation de données sur le site Autovisual.com (https://www.autovisual.com/fr/voiture-occasion/Audi/A5/A5_Sportback--Grande_Berline/fr--75000--Paris/graph).

En 2014/2015, backbonejs et marionettejs faisaient office d’’outil parfait pour faire du MVC (Modele Vue Controler). Par exemple, pour l’affichage d’une collection de voitures, il s’agit de Vues (une carte, un graphique, des histogrammes) et d’un controller, le Router, qui gère l’URL du navigateur. Les nombreuses révolutions pour afficher les données, i.e. côté front, ont généré la “JavaScript fatigue” chez les développeurs, (source : https://medium.com/@ericclemmons/javascript-fatigue-48d4011b6fc4). A peine une technologie est-elle implémentée avec le temps nécessaire à la finition du produit que la technologie est déjà obsolète.

AutoVisual n’a pas migré vers des frameworks plus récents. L’arrivée du Service Worker et la facilité de mise en place de cette technologie en 3 jours rend les implémentations techniques très compétitive. C’est ce que nous allons détailler ici.

L’intégralité du code d’Autovisual pèse 235Ko de JavaScript compressé au format GZIP, soit l’équivalent de 4 photos Instagram. Cela représente donc une bonne minification de tout le code JavaScript, backbonejs et marionettejs étant des petites librairies. Dans le monde des Service Workers, cela s’appelle “App Shell”. Il s’agit de la coquille qui fait que même hors connexion le site va pouvoir s’afficher à condition que :

  • le navigateur supporte la technologie Service Worker (aujourd’hui Chrome et Firefox) ;
  • il a déjà cette App Shell d’une précédente visite ce qui permet aux appels Ajax précédemment sauvegardés d’être rejoués.

Note : Ce guide est compatible avec les architectures Angular et Vue qui ont un Router et un noyau autonome (App Shell).

Programmer un Service Worker depuis le départ est complexe : de nouvelles commandes JavaScript relativement complexes, un potentiel de dingue mais une documentation faible.

Heureusement Google est là, et a sorti la librairie “Workbox” (https://github.com/GoogleChrome/workbox) qui va nous faciliter le travail.

Grâce à cette librairie, on va pouvoir facilement définir nos stratégies de cache de tous les appels réseaux déclenchés par la navigation d’AutoVisual.com . Ainsi, en cas de coupure de réseaux, nos petits appels Ajax mis en cache vont prendre le relais pour fournir une bonne expérience utilisateur (voir figure 2).


Fig. 2. Expérience utilisateur sur le site Autovisual.com.

 

Le code

Tout d'abord, on installe la librairie :

npm install workbox-cli --global

Premièrement, il faut indiquer à Workbox son “App Shell” : tous les fichiers importants que le navigateur devrait déclencher en téléchargement, au cas où la connexion Internet est interrompue, pour qu'à une prochaine visite, le site puisse rester fonctionnel.

Contenu du build-sw.js d’AutoVisual

On indique donc ensuite le répertoire où il doit scanner les images et les fichiers style (CSS) nécessaires à AutoVisual (globDirectory , globPatterns , globIgnores).
Se référer à la documentation en ligne pour en savoir plus : https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-build

(code source issu de http://www.planetb.ca/syntax-highlight-word)

const workboxBuild = require('workbox-build');

workboxBuild.injectManifest({
"globDirectory": "../public/",
"globPatterns": [
"**/*.{png,eot,svg,ttf,woff,woff2,gif,jpg}", "all.min.css", "workbox-sw.*.map","manifest.json"
],
"templatedUrls": {
'/': ['../views/index.html', 'all.min.css', "jsprod/all_fr.min.js"],
},
"swSrc": "./swSrc.js",
"swDest": "../public/sw.js",
"globIgnores": [
"../workbox-cli-config.js", "img/thumbs/*", "mstile*", "presse/signature/*", "js/**", "jsprod/*.map","img/blog/*"
]
})
.then(() => {
console.log('Service worker generated.');
});

 

Contenu de swSrc.js

On y définit nos stratégies de cache :
https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-sw.Strategies

Seules sont utilisées pour l’instant, les fonctions :

  • cacheFirst : on regarde d’abord si on a déjà fait cet appel, si oui, on utilise le résultat.

Pour les appels Ajax qui ne bougent pas (résultat du moteur de recherche, utilitaires de navigation) :

  • networkFirst : on fait un appel au serveur, si pas de réponse, on regarde dans le cache.
    Pour les appels Ajax décisifs, on charge les audi a5 à Paris, il faut les plus récentes.
  • staleWhileRevalidate : on prend la version en cache en même temps qu’un appel au serveur, on donne à l’utilisateur tout de suite la version en cache, mais si le serveur répond, on met à jour la version de cache pour la prochaine fois) pourrait être intéressant dans ce cas.

 

importScripts('workbox-sw.prod.v2.1.2.js');
// self.workbox.logLevel = self.workbox.LOG_LEVEL.verbose;

const workboxSW = new WorkboxSW({
clientsClaim: true,
skipWaiting: true,
ignoreUrlParametersMatching: [/^(utm_|v_sw_ignore)/]
});

workboxSW.precache([]);

workboxSW.router.registerRoute(/json-(cote|veh|geo|nav-search|nav-valuation|similar)/,
workboxSW.strategies.cacheFirst({
cacheName: 'jsonCacheFirst',
cacheExpiration: {
maxEntries: 100,
maxAgeSeconds: 24 * 60 * 60 * 10 // 10jours
}
})
);

workboxSW.router.registerRoute(/(json-(modele|more-modele|budget)|unlockValuation|consoInfo|apiGetKey)/,
workboxSW.strategies.networkFirst({
cacheName: 'jsonNetworkFirst',
cacheExpiration: {
maxEntries: 500,
maxAgeSeconds: 24 * 60 * 60 * 5
}
})
);

workboxSW.router.registerRoute(/.*.(?:png|jpg|jpeg|gif)$/,
workboxSW.strategies.networkFirst({
cacheName: 'adsImgCache',
cacheExpiration: {
maxEntries: 2000
}
})
);

workboxSW.router.registerRoute('/fonts.gstatic.com/',
workboxSW.strategies.cacheFirst({
cacheName: 'googleapis',
cacheableResponse: {
statuses: [0, 200]
}
})
);

workboxSW.router.setDefaultHandler({
handler: ({
event
}) => {
return fetch(event.request);
},
});

workboxSW.router.setCatchHandler({
handler: ({
event
}) => {
if (event.request.mode === 'navigate') {
return caches.match('/');
}
return new Response();
},
});

 

Les lignes :

  if (event.request.mode === 'navigate') {
return caches.match('/');
}

sont pour le cas de rupture de connexion Internet et une tentative d'accès à une page profonde : on redirige vers la home “/” , et l’App Shell qui connait toutes les URLs (grâce à la technologie backbonejs qui embarque un Router) saura quoi faire. C’est pour cette raison que dans build-sw.js au début du tuto, on indique la ligne :

"templatedUrls": {
'/': ['../views/index.html', 'all.min.css', "jsprod/all_fr.min.js"],
},

On configure le Service Worker pour dire au navigateur de télécharger l’URL “/” .

Puis on lance :

node build-sw.js

Il génère le Service Worker et sa librairie :

../public/sw.js
../public/workbox-sw.prod.v2.1.2.js

Dans notre JavaScript en front, on insère ces lignes, pour dire au navigateur compatible l'existence du Service Worker :

if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js', {
scope: "/"
});
}

Puis, il faut bien adapter l’affichage en front avec des jolis messages “Vérifiez votre connexion Internet” (Fig. 3).


Fig. 3. résultat affiché sur le site Autovisual.com.

En conclusion, Workbox est réellement génial ! Enfin une librairie claire qui répond aux problématiques classiques pour faire une bonne PWA facilement.

Pour en savoir plus, n'hésitez pas à lire cette page web, qui montre bien toutes le sfonctionnalités de Google Chrome pour débugger un service worker dans Google Chrome :
https://developers.google.com/web/fundamentals/codelabs/debugging-service-workers/

Et maintenant, à vos claviers ! 🙂


Audrey Schoonwater, Consultant SEO / Chef de projet Technique (http://audreyschoonwater.fr/)