Sur l'application installee sur telephone, le bandeau restait sans effet et
le chargement se figeait a 100 %. La capture montrait le bandeau SANS son
CSS, alors que le script et sa regle sont arrivés dans le meme commit : ce
n'etait pas une mise a jour qui ne s'applique pas, mais une mise a jour
appliquee a moitie.
- MapFallbackToFile n'heritait pas des StaticFileOptions : « / », le
start_url de la PWA, repartait sans Cache-Control (mesure), donc en cache
heuristique. A1 avait couvert tous les fichiers statiques sauf celui-la.
- register('service-worker.js') se resolvait contre l'URL du document et non
contre <base> : une ouverture sur une route profonde visait
/souhaits/service-worker.js, qui repond 404 (verifie). Tout le hors-ligne
tombait alors en silence.
- clients.claim() et un rechargement force borne a une fois par session
donnent un filet a la chaine SKIP_WAITING -> controllerchange -> reload.
- Une version prete dans les 10 s suivant l'ouverture s'applique seule, sans
bandeau ; au-dela on repasse par le clic, pour ne pas arracher une saisie.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
72 lines
3.7 KiB
JavaScript
72 lines
3.7 KiB
JavaScript
// Caution! Be sure you understand the caveats before publishing an application with
|
|
// offline support. See https://aka.ms/blazor-offline-considerations
|
|
|
|
self.importScripts('./service-worker-assets.js');
|
|
self.addEventListener('install', event => event.waitUntil(onInstall(event)));
|
|
self.addEventListener('activate', event => event.waitUntil(onActivate(event)));
|
|
self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
|
|
|
|
// Mise à jour à la demande. Sans cela, un nouveau worker attend que TOUS les onglets de
|
|
// l'application soient fermés — un onglet oublié fige indéfiniment l'utilisateur sur l'ancienne
|
|
// version. C'est d'autant plus important ici que les empreintes des assets WASM sont désactivées
|
|
// (voir CLAUDE.md) : ce worker est le SEUL mécanisme de cache-busting du projet.
|
|
// Le message ne vient que de js/mise-a-jour.js, après un clic explicite : jamais tout seul, pour
|
|
// ne pas mélanger deux versions au milieu d'une session.
|
|
self.addEventListener('message', event => {
|
|
if (event.data && event.data.type === 'SKIP_WAITING') self.skipWaiting();
|
|
});
|
|
|
|
const cacheNamePrefix = 'offline-cache-';
|
|
const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`;
|
|
const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/, /\.webmanifest$/ ];
|
|
const offlineAssetsExclude = [ /^service-worker\.js$/ ];
|
|
|
|
// Replace with your base path if you are hosting on a subfolder. Ensure there is a trailing '/'.
|
|
const base = "/";
|
|
const baseUrl = new URL(base, self.origin);
|
|
const manifestUrlList = self.assetsManifest.assets.map(asset => new URL(asset.url, baseUrl).href);
|
|
|
|
async function onInstall(event) {
|
|
console.info('Service worker: Install');
|
|
|
|
// Fetch and cache all matching items from the assets manifest
|
|
const assetsRequests = self.assetsManifest.assets
|
|
.filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url)))
|
|
.filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url)))
|
|
.map(asset => new Request(asset.url, { integrity: asset.hash, cache: 'no-cache' }));
|
|
await caches.open(cacheName).then(cache => cache.addAll(assetsRequests));
|
|
}
|
|
|
|
async function onActivate(event) {
|
|
console.info('Service worker: Activate');
|
|
|
|
// Delete unused caches
|
|
const cacheKeys = await caches.keys();
|
|
await Promise.all(cacheKeys
|
|
.filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName)
|
|
.map(key => caches.delete(key)));
|
|
|
|
// Prendre la main sur les pages déjà ouvertes. skipWaiting() est censé le faire seul, mais
|
|
// c'est ce qui déclenche `controllerchange`, donc le rechargement côté page : sans reprise
|
|
// effective, le bouton « Mettre à jour » se grise et il ne se passe plus rien — symptôme
|
|
// observé sur téléphone. Cet appel est sans effet quand la reprise a déjà eu lieu.
|
|
await self.clients.claim();
|
|
}
|
|
|
|
async function onFetch(event) {
|
|
let cachedResponse = null;
|
|
if (event.request.method === 'GET') {
|
|
// For all navigation requests, try to serve index.html from cache,
|
|
// unless that request is for an offline resource.
|
|
// If you need some URLs to be server-rendered, edit the following check to exclude those URLs
|
|
const shouldServeIndexHtml = event.request.mode === 'navigate'
|
|
&& !manifestUrlList.some(url => url === event.request.url);
|
|
|
|
const request = shouldServeIndexHtml ? 'index.html' : event.request;
|
|
const cache = await caches.open(cacheName);
|
|
cachedResponse = await cache.match(request);
|
|
}
|
|
|
|
return cachedResponse || fetch(event.request);
|
|
}
|