Comment j'ai pourri le cache de mes lecteurs avec une PWA foireuse (et comment j'ai réparé ça) | Tendances web | Le site de Korben
Image illustrant l'article : Comment j'ai pourri le cache de mes lecteurs avec une PWA foireuse (et comment j'ai réparé ça)

Comment j'ai pourri le cache de mes lecteurs avec une PWA foireuse (et comment j'ai réparé ça)

par Korben ✨ -

Bon, aujourd’hui je vais vous raconter une belle connerie que j’ai faite sur mon site. Vous savez, ces moments où vous vous dites “tiens, je vais tester un truc cool” et où ça finit en catastrophe… Bah voilà, c’est exactement ce qui m’est arrivé avec une Progressive Web App.

L’idée de départ était sympa pourtant, j’avais envie que mes lecteurs puissent consulter mes articles même sans connexion, genre dans le métro ou en avion. Et les PWA, c’est fait pour ça puisque ça met en cache une partie du site pour permettre une consultation offline. Sur le papier, c’est génial mais je viens d’apprendre à mes dépend que dans la vraie vie, c’est une autre histoire…

J’ai donc mis en place ma petite PWA tranquillement, avec mon Service Worker qui faisait son boulot de mise en cache. Sauf que voilà, ça marchait pas terrible. Des bugs par-ci, des trucs qui s’affichaient mal par-là, bref c’était pas au point. Du coup, j’ai décidé de tout virer et de revenir à un site classique. Simple, non ?

Eh bah non, pas simple du tout ! Parce que les Service Workers, c’est un peu comme des invités qui squattent votre canapé un samedi soir et qui veulent plus en partir. Une fois qu’ils sont installés dans le navigateur de vos visiteurs, ils y restent pour de bon !! Et même si vous supprimez tous les fichiers côté serveur, eux ils s’en foutent royal et continuent de servir la vieille version en cache.

Le pire dans tout ça, c’est que je ne peux pas contacter individuellement chaque visiteur pour lui dire “Hey, vide ton cache s’il te plaît, mortecouille !”. Et même si je le pouvais, la plupart des gens savent même pas comment faire… Bref, une partie de mes lecteurs étaient bloqués sur une vieille version pourrie de mon site, et moi je me tapais la tête contre les murs.

Heureusement, après pas mal de recherches et quelques cheveux en moins, j’ai trouvé LA solution. En fait, il faut mettre en place une stratégie de terre brûlée pour forcer ces satanés Service Workers à dégager fissa !

Je vais donc vous expliquer comment j’ai fait, parce que comme ça, ça pourra servir à d’autres. D’abord, j’ai créé un nouveau fichier sw.js minimaliste dont le seul but dans la vie est de s’autodétruire :

self.addEventListener('install', () => self.skipWaiting());
self.addEventListener('activate', e => e.waitUntil(
clients.claim().then(() => 
caches.keys().then(names => 
Promise.all(names.map(name => caches.delete(name)))
).then(() => self.registration.unregister())
)
));

Ce petit bout de code fait 3 trucs essentiels : il prend le contrôle immédiatement (skipWaiting), il vide tous les caches, et surtout, il se désinstalle lui-même. C’est un peu comme un virus mais en version sympa qui nettoie tout sur son passage.

Mais c’était pas suffisant. Il fallait aussi que je m’assure que ce nouveau Service Worker soit bien téléchargé par tous les navigateurs. Pour ça, j’ai donc dû sortir l’artillerie lourde avec un .htaccess aux petits oignons que voici :

<IfModule mod_headers.c>
<FilesMatch "^(sw|service-worker|serviceworker)\.js$">
# La bombe nucléaire : Clear-Site-Data
Header always set Clear-Site-Data "\"cache\", \"storage\""

# Belt and suspenders : on empêche toute mise en cache
Header always set Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0"
Header always set Pragma "no-cache"
Header always set Expires "0"

# On vire l'ETag pour être sûr
Header always unset ETag
FileETag None

# Et on met une date bidon pour forcer le rechargement
Header always set Last-Modified "Thu, 01 Jan 1970 00:00:00 GMT"
</FilesMatch>
</IfModule>

Le header Clear-Site-Data, c’est la grosse bertha de la gestion de cache. Il dit au navigateur “vire-moi tout ce bordel maintenant”. C’est supporté par la plupart des navigateurs modernes et c’est ultra efficace.

Ce qui est marrant (enfin, façon de parler), c’est que j’aurais pu éviter tout ce cirque si j’avais mieux préparé mon coup dès le départ. Genre, prévoir un “kill switch” dans mon Service Workers, c’est à dire un truc qui permet de les désactiver à distance. Ou encore mieux, utiliser un système de versioning automatique pour forcer les mises à jour.

Les développeurs qui ont déjà galéré avec ça savent de quoi je parle. Pour les autres, quelques conseils en vrac pour éviter de tomber dans le même piège :

Déjà, y’a des outils sympas pour débugger tout ça. Dans Chrome, vous pouvez aller sur chrome://serviceworker-internals/ pour voir tous les Service Workers actifs. Ou alors, direct dans la console comme ceci :

// Pour voir tous les Service Workers
navigator.serviceWorker.getRegistrations().then(console.log);

// Pour voir tous les caches
caches.keys().then(console.log);

Un truc important aussi, évitez de hasher le nom de votre Service Worker (genre sw.a1b2c3.js). Ça peut sembler malin pour forcer les mises à jour, mais en fait ça empêche le navigateur de détecter qu’il y a une nouvelle version. Et sur iOS Safari, c’est encore pire, puisqu’il faut parfois forcer un window.location.reload(true) pour que ça passe.

Oh, et méfiez-vous des CDN ! Même avec tous les bons headers, certains CDN peuvent mettre en cache votre Service Worker et foutre le bordel. Vérifiez donc toujours votre config CDN si vous en utilisez un.

Bref, tout ça pour dire que les PWA, c’est cool mais faut y aller avec des pincettes. Si vous voulez tester, préparez bien votre stratégie de sortie dès le départ parce que croyez-moi, nettoyer le cache de milliers de visiteurs après coup, c’est pas une partie de plaisir.

Maintenant, mon site fonctionne nickel pour tout le monde. Je vais devoir quand même attendre quelques semaines pour être sûr que tous les caches seront bien nettoyés. Maintennt, est-ce que je retenterai l’expérience PWA un jour ? Peut-être, mais cette fois avec un plan B, un plan C, et même un plan D au cas où. On est jamais trop prudent avec ces trucs-là !

Bref, j’espère que mon malheur servira au moins à quelques-uns d’entre vous.