-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsw.js
More file actions
180 lines (161 loc) · 6.27 KB
/
Copy pathsw.js
File metadata and controls
180 lines (161 loc) · 6.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
const CACHE_NAME = 'logpose-v329';
const STATIC_ASSETS = [
'/',
'/index.html',
'/game.html', // redirection vers /classique/ (ancienne URL, favoris)
'/versus.html',
'/en/',
'/en/index.html',
'/en/game.html', // redirection vers /en/classic/
'/en/versus.html',
// Une page par mode (chantier SEO) : 16 documents d'environ 34 Ko. Les
// précacher permet de changer de mode hors ligne — c'est désormais une
// navigation, plus une bascule JS. Coût : ~550 Ko à l'installation, en
// arrière-plan (l'événement install ne bloque pas l'affichage).
'/classique/',
'/wanted/',
'/silhouette/',
'/fruit-du-demon/',
'/emoji/',
'/opening/',
'/tome/',
'/infini/',
'/en/classic/',
'/en/wanted/',
'/en/silhouette/',
'/en/devil-fruit/',
'/en/emoji/',
'/en/opening/',
'/en/volume/',
'/en/endless/',
'/js/i18n.js?v=329',
'/i18n/en.js?v=329',
'/css/versus.css?v=329',
'/js/versus.js?v=329',
'/css/base.css?v=329',
'/css/landing.css?v=329',
'/css/layout.css?v=329',
'/css/modals.css?v=329',
'/css/classic.css?v=329',
'/css/wanted.css?v=329',
'/css/silhouette.css?v=329',
'/css/fruit.css?v=329',
'/css/inf.css?v=329',
'/css/emoji.css?v=329',
'/css/misc.css?v=329',
'/css/audio.css?v=329',
'/js/version.js?v=329',
'/js/data.js?v=329',
'/js/landing.js?v=329',
'/js/jolly-roger.js?v=329',
'/js/versus-rules.js?v=329',
'/js/app.js?v=329',
'/js/canvas-share.js?v=329',
'/js/map.js?v=329',
'/css/animations.css?v=329',
'/css/map.css?v=329',
'/css/tome.css?v=329',
'/css/ocean3d.css?v=329',
'/css/answers.css?v=329',
'/css/mobile.css?v=329',
'/js/ocean3d-boot.js?v=329',
'/data.json',
'/calendar.json',
'/manifest.json',
'/manifest.en.json',
'/images/jolly_roger_sm.webp',
'/images/favicon.png',
'/images/going_merry_sm.webp',
];
// Volontairement HORS précache (récupérés par le runtime si besoin) :
// /js/ocean3d.js 110 Ko — fond 3D chargé à la demande depuis la v6.5
// /images/og_preview.jpg 75 Ko — vignette de partage, jamais affichée sur le site
// /images/wanted_frame.webp — n'est utile qu'en mode Wanted
// Installation : mise en cache des assets essentiels
self.addEventListener('install', event => {
self.skipWaiting();
event.waitUntil(
caches.open(CACHE_NAME).then(cache => cache.addAll(STATIC_ASSETS)).catch(() => {})
);
});
// Activation : nettoyage des anciens caches
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys =>
Promise.all(keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k)))
).then(() => self.clients.claim())
);
});
// ============================================================
// STRATÉGIE DE CACHE (revue en v6.5)
// ------------------------------------------------------------
// Avant : network-first sur TOUT le JS/CSS/JSON. Or ces URL portent déjà
// ?v=NNN : elles sont immuables par construction. On re-téléchargeait donc
// ~730 Ko à chaque partie quotidienne pour obtenir un contenu déjà en cache,
// et sans timeout — en 4G dégradée (métro, tunnel) la requête ne rate pas,
// elle traîne, et le repli cache ne se déclenchait jamais.
//
// Maintenant :
// • URL versionnée (?v=) -> CACHE-FIRST (immuable, 0 octet réseau)
// • HTML et data.json -> NETWORK-FIRST avec timeout, repli cache
// • images et le reste -> CACHE-FIRST
// Le HTML reste en network-first : c'est lui qui porte les nouveaux ?v=,
// donc c'est lui qui déclenche la mise à jour de tout le reste.
// ============================================================
const NET_TIMEOUT_MS = 3000;
// Met en cache une réponse valable uniquement (pas les 404, pas les opaques)
function putIfOk(request, response) {
if (!response || !response.ok || response.type === 'opaque') return response;
const clone = response.clone();
caches.open(CACHE_NAME).then(cache => cache.put(request, clone)).catch(() => {});
return response;
}
// Réseau d'abord, mais on n'attend pas indéfiniment : passé NET_TIMEOUT_MS,
// on sert la version en cache s'il y en a une (le réseau continue en fond
// et rafraîchit le cache pour la prochaine fois).
async function networkFirst(request) {
// Le fetch continue en arrière-plan même si on répond depuis le cache :
// le cache est ainsi rafraîchi pour la visite suivante.
const reseau = fetch(request).then(res => putIfOk(request, res));
// Course entre le réseau et le chronomètre.
const chrono = new Promise(resolve => setTimeout(() => resolve(null), NET_TIMEOUT_MS));
const gagnant = await Promise.race([reseau.catch(() => null), chrono]);
if (gagnant) return gagnant;
// Réseau trop lent ou en échec : on sert le cache s'il a la ressource.
const cache = await caches.match(request);
if (cache) return cache;
// Rien en cache : on laisse le réseau aller au bout (et remonter son erreur).
return reseau;
}
function cacheFirst(request) {
return caches.match(request).then(cached => {
if (cached) return cached;
return fetch(request).then(res => putIfOk(request, res));
});
}
self.addEventListener('fetch', event => {
if (event.request.method !== 'GET') return;
const url = new URL(event.request.url);
// Ne pas intercepter les requêtes externes (fonts, Firebase, three.js CDN…)
if (url.origin !== self.location.origin) return;
// Ne pas intercepter les requêtes audio (MP3) — toujours depuis le réseau
if (url.pathname.startsWith('/audio/')) return;
// Une URL versionnée (?v=NNN) est immuable par construction : son contenu ne
// changera jamais, seul le HTML pointera un jour vers un autre ?v=.
if (url.searchParams.has('v')) {
event.respondWith(cacheFirst(event.request));
return;
}
// Non versionné et susceptible de changer : le HTML (qui porte les nouveaux
// ?v=) et les JSON (data.json quand des personnages sont ajoutés,
// manifest*.json quand la PWA évolue). Sans cette règle, un manifeste mis en
// précache ne serait plus jamais rafraîchi.
const estHTML = url.pathname.endsWith('.html') || url.pathname.endsWith('/');
const estJSON = url.pathname.endsWith('.json');
if (estHTML || estJSON) {
event.respondWith(networkFirst(event.request));
return;
}
// Images, polices, et tout le reste : immuables en pratique.
event.respondWith(cacheFirst(event.request));
});