frontend: Update-Erkennung über vollen Content-Hash statt 300-Zeichen-Fenster
Die Erkennung hashte nur die ersten + letzten 300 Zeichen der Seite. Da der Editor eine self-contained Datei ist (D19), liegen der gesamte App-Code UND die Footer-Version als inline-Bundle in der Mitte — außerhalb des abgetasteten Fensters. Anfang/Ende sind Build-übergreifend identisch, daher wurde eine neue Version nie erkannt (nur die ETag änderte sich -> "Metadaten geändert, aber Inhalt gleich"). - hashContent() (cyrb53) über den GESAMTEN Text als alleinige Wahrheit. - ETag/Last-Modified-Vergleich entfernt: GitHub Pages liefert je Cache-Knoten wechselnde ETags für identischen Inhalt und löste damit die irreführende Metadaten-Meldung aus. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
29e144eddf
commit
17d354059e
+24
-25
@@ -1229,50 +1229,49 @@ mountBuildBadge();
|
|||||||
ALLEN Builds aktiv. */
|
ALLEN Builds aktiv. */
|
||||||
const isProdBuild = import.meta.env.VITE_BUILD_BADGE === 'none';
|
const isProdBuild = import.meta.env.VITE_BUILD_BADGE === 'none';
|
||||||
|
|
||||||
|
/* Kompakter, deterministischer Hash (cyrb53) über den GESAMTEN HTML-Text.
|
||||||
|
Wichtig: Der frühere Ansatz „erste 300 + letzte 300 Zeichen" verfehlte JEDE
|
||||||
|
Änderung — die Seite ist eine self-contained Datei (D19), der komplette
|
||||||
|
App-Code UND die Footer-Version liegen als inline-Bundle in der MITTE, also
|
||||||
|
außerhalb des abgetasteten Fensters. Anfang/Ende sind Build-übergreifend
|
||||||
|
identisch. Nur ein Hash über den vollen Text erkennt neue Deployments. */
|
||||||
|
function hashContent(str){
|
||||||
|
let h1 = 0xdeadbeef, h2 = 0x41c6ce57;
|
||||||
|
for(let i = 0; i < str.length; i++){
|
||||||
|
const ch = str.charCodeAt(i);
|
||||||
|
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||||
|
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||||
|
}
|
||||||
|
h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909);
|
||||||
|
h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909);
|
||||||
|
return (4294967296 * (2097151 & h2) + (h1>>>0)).toString(36);
|
||||||
|
}
|
||||||
|
|
||||||
async function checkForUpdates(){
|
async function checkForUpdates(){
|
||||||
try {
|
try {
|
||||||
/* Fetch HTML mit Cache-Busting via Timestamp */
|
/* Fetch HTML mit Cache-Busting via Timestamp */
|
||||||
const resp = await fetch(location.href + '?t=' + new Date().getTime(), { cache: 'no-store' });
|
const resp = await fetch(location.href + '?t=' + new Date().getTime(), { cache: 'no-store' });
|
||||||
if(!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
if(!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
||||||
|
|
||||||
|
/* Voller Content-Hash ist die alleinige Wahrheit. ETag/Last-Modified werden
|
||||||
|
bewusst NICHT mehr herangezogen: GitHub Pages liefert je Cache-Knoten
|
||||||
|
unterschiedliche ETags für identischen Inhalt und löste damit die
|
||||||
|
irreführende Meldung „Metadaten geändert, aber Inhalt gleich" aus. */
|
||||||
const html = await resp.text();
|
const html = await resp.text();
|
||||||
const lastModified = resp.headers.get('last-modified');
|
const hash = hashContent(html);
|
||||||
const etag = resp.headers.get('etag');
|
|
||||||
|
|
||||||
/* Prüfe auf echte Änderung via Content-Hash */
|
|
||||||
const stored = localStorage.getItem('werkbaum-html-hash');
|
const stored = localStorage.getItem('werkbaum-html-hash');
|
||||||
const hash = html.substring(0, 300) + html.substring(html.length - 300);
|
|
||||||
|
|
||||||
/* Vergleich: ETag/Last-Modified ODER Content-Hash */
|
|
||||||
const storedETag = localStorage.getItem('werkbaum-etag');
|
|
||||||
const storedModified = localStorage.getItem('werkbaum-last-modified');
|
|
||||||
const headersSame = (etag && etag === storedETag) || (lastModified && lastModified === storedModified);
|
|
||||||
const contentSame = stored && stored === hash;
|
|
||||||
|
|
||||||
if(contentSame && headersSame){
|
|
||||||
if(!stored){
|
if(!stored){
|
||||||
logUpdate('✓ Erste Prüfung – Hash gespeichert');
|
logUpdate('✓ Erste Prüfung – Hash gespeichert');
|
||||||
} else {
|
} else if(hash === stored){
|
||||||
logUpdate('✓ Alles aktuell');
|
logUpdate('✓ Alles aktuell');
|
||||||
}
|
|
||||||
} else if(contentSame && !headersSame){
|
|
||||||
/* Content gleich, aber Headers geändert – wahrscheinlich nur Build-Metadaten */
|
|
||||||
if(!stored) {
|
|
||||||
logUpdate('✓ Erste Prüfung – Hash gespeichert');
|
|
||||||
} else {
|
} else {
|
||||||
logUpdate('⚙ Metadaten geändert, aber Inhalt gleich');
|
|
||||||
}
|
|
||||||
} else if(stored && !contentSame) {
|
|
||||||
localStorage.setItem('werkbaum-update-available', 'true');
|
localStorage.setItem('werkbaum-update-available', 'true');
|
||||||
logUpdate('✅ NEUE VERSION ERKANNT!');
|
logUpdate('✅ NEUE VERSION ERKANNT!');
|
||||||
if(!document.hidden) checkAndShowUpdateNotification();
|
if(!document.hidden) checkAndShowUpdateNotification();
|
||||||
} else if(!stored) {
|
|
||||||
logUpdate('✓ Erste Prüfung – Hash gespeichert');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage.setItem('werkbaum-html-hash', hash);
|
localStorage.setItem('werkbaum-html-hash', hash);
|
||||||
if(etag) localStorage.setItem('werkbaum-etag', etag);
|
|
||||||
if(lastModified) localStorage.setItem('werkbaum-last-modified', lastModified);
|
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
const msg = err.message || err.toString();
|
const msg = err.message || err.toString();
|
||||||
if(msg.includes('Failed to fetch')) {
|
if(msg.includes('Failed to fetch')) {
|
||||||
|
|||||||
Reference in New Issue
Block a user