Webmastering PWA

Comme vous avez pu le constater (sans en connaitre le nom), ce site utilise un Service Worker, c’est un PWA (Progressive Web Apps)

Pour vulgariser, cela permet de transformer un site web en application,
cela permet aussi de dire quoi faire en cas de panne de réseau, par exemple envoyer un message qui n’a pu être transmis quand le réseau était indisponible, ou bien télécharger une page web une fois le réseau rétabli.

En principe ce site est parfaitement fonctionnel en cas de panne de réseau, vous pouvez aussi en faire une application sur votre téléphone ou sur votre ordinateur,
Pas de panique il ne s’agit la que de pages web classiques en HTML et en JavaScript, aucune application n’est réellement installée sur l’appareil et nous n’avons aucun moyen de collecter d’informations et n’utilisons pas de système de notification.

En résumé, un site PWA est capable de fonctionner sans réseau en mettant en attente les requêtes quand nécessaire et peu s’afficher comme une application, d’autres fonctions existent comme les notifications, mais nous ne les utilisons pas.

Pour mettre en place un site en PWA, vous n’avez pas besoin d’une configuration serveur particulière autre qu’avoir un site en HTTPS donc cela fonctionne même avec un hébergement mutualisé.

Pour cela il vous faut un Service Worker et le déclarer.

Service Worker

La déclaration se fait comme ceci

if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('/sw.js').then(function(registration) {
      // Registration was successful
      console.log('ServiceWorker registration successful with scope: ', registration.scope);
    }, function(err) {
      // registration failed :(
      console.log('ServiceWorker registration failed: ', err);
    });
  });
}

sw.js étant le nom de votre Service Worker a la racine « /«

Ensuite il faut créer le Service Worker, celui que nous utilisons contient ceci

//Nom du cache, ici le nom du site
const cacheName = 'autistes.ovh';
//Page d'ouverture du site
const startPage = 'https://autistes.ovh';
//Page en cas d’accès hors réseau a une page qui n'est pas en cache
const offlinePage = 'https://autistes.ovh/erreur-reseau/';
//Les fichiers a mettre en page
const filesToCache = [startPage, offlinePage, {LISTE_IMAGES_ET_PAGES}];
//Les adresses a ne pas mettre en cache, ici pour un wordpress il s'agit de la page d'administration, de connexion et les articles prévisualisé
const neverCacheUrls = [//wp-admin/, //wp-login/, /preview=true/, /share=/'];

// Installation, action effecté au moment de la première visite ou quand le SW est mis à jour
self.addEventListener('install', function(e) {
    console.log('Service worker installation');
    e.waitUntil(
        caches.open(cacheName).then(function(cache) {
            //Mise en cache des dépandances les fichiers listé dans filesToCache
            console.log('Service worker caching dependencies');
            filesToCache.map(function(url) {
                return cache.add(url).catch(function(reason) {
                    return console.log('SW: ' + String(reason) + ' ' + url);
                });
            });
        })
    );
});

// Activation, effectué suite a une installation
self.addEventListener('activate', function(e) {
    console.log('Service worker activation');
    //Suppression du cache en cas de changement du nom du cache
    e.waitUntil(
        caches.keys().then(function(keyList) {
            return Promise.all(keyList.map(function(key) {
                if (key !== cacheName) {
                    console.log('Old cache removed', key);
                    return caches.delete(key);
                }
            }));
        })
    );
    return self.clients.claim();
});

// Fetch, quand une page est chargé
self.addEventListener('fetch', function(e) {

    // Return if the current request url is in the never cache list
    if (!neverCacheUrls.every(checkNeverCacheList, e.request.url)) {
        console.log('SuperPWA: Current request is excluded from cache.');
        return;
    }

    // Return if request url protocal isn't http or https
    if (!e.request.url.match(/^(http|https):\/\//i))
        return;

    // Return if request url is from an external domain.
    if (new URL(e.request.url).origin !== location.origin)
        return;

    // For POST requests, do not use the cache. Serve offline page if offline.
    if (e.request.method !== 'GET') {
        e.respondWith(
            fetch(e.request).catch(function() {
                return caches.match(offlinePage);
            })
        );
        return;
    }

    if (e.request.mode === 'navigate') {
        // Instead of https://example.com/page?key=value,
        // use https://example.com/page when reading and writing to the cache.
        // For static HTML documents, it's unlikely your query parameters will
        // affect the HTML returned. But if you do use query parameters that
        // uniquely determine your HTML, modify this code to retain them.
        const normalizedUrl = new URL(e.request.url);
        if (normalizedUrl.href.includes('relatedposts_hit')) {
            normalizedUrl.search = '';
        }

        // See /web/fundamentals/getting-started/primers/async-functions
        // for an async/await primer.
        e.respondWith(async function() {

            // Create promises for both the network response,
            // and a copy of the response that can be used in the cache.
            const fetchResponseP = fetch(normalizedUrl);
            const fetchResponseCloneP = fetchResponseP.then(r => r.clone());

            // event.waitUntil() ensures that the service worker is kept alive
            // long enough to complete the cache update.
            e.waitUntil(async function() {
                const cache = await caches.open(cacheName);
                await cache.put(normalizedUrl, await fetchResponseCloneP);
                await filesToCache.map(function(url) {
                    cache.add(url).catch(function(reason) {
                        console.log('SuperPWA: ' + String(reason) + ' ' + url);
                    });
                });
            }());

            // Prefer the cached response, falling back to the fetch response.
            return (await caches.match(normalizedUrl)) || fetchResponseP;
        }());
    } else {

        e.respondWith(
            caches.match(e.request).then(function(response) {
                return response || fetch(e.request).then(function(response) {
                    return caches.open(cacheName).then(function(cache) {
                        cache.put(e.request, response.clone());
                        return response;
                    });
                });
            }).catch(function() {
                return caches.match(offlinePage);
            })
        );
    }
});

// Verification de neverCacheUrls
function checkNeverCacheList(url) {
    if (this.match(url)) {
        return false;
    }
    return true;
}

Une fois se fichier créé et sa déclaration faite votre site est mis en cache, du mois les pages visités et celles que vous avez déclarées en dépendance, pour que votre site supporte PWA il vous faut ensuite un manifeste

Manifeste

C’est très simple, il suffit de faire un fichier JSON décrivant le site PWA,
Dans notre cas il s’agit de ce fichier

{
  "name": "Autistes Adultes",
  "short_name": "Autistes A.",
  "icons": [
    {
      "src": "https://autistes.ovh/wp-content/uploads/2020/01/sqlogo-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "https://autistes.ovh/wp-content/uploads/2020/01/sqlogo-512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "background_color": "#D5E0EB",
  "theme_color": "#D5E0EB",
  "display": "fullscreen",
  "orientation": "portrait",
  "start_url": ".",
  "scope": "/"
}

Je pense que les arguments sont assez simples à comprendre, si vous souhaitez en savoir plus regarder cette documentation.

Il vous faudra aussi déclarer ce fichier dans votre code HTML.

<link rel="manifest" href="/manifest.json">

Conclusion

Normalement avec ces simples ajouts à votre site, un SW et un manifeste celui-ci devrait pleinement prendre en charge PWA.

Si vous avez des questions, besoin d’aide pour la mise en place d’un PWA n’hésitez pas à me demander.

Plus tard je parlerais peut-être de comment automatiser la génération du SW.
Aussi il me reste à vous présenter les autres optimisations effectuées pour ce site, tels la mise en cache Redis et Pagespeed.

Mais c’est tout pour le moment.

Auteur : Benoît Anastay

Juste un autiste avec deux yeux. 

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.