Jede Seite erklaert sich selbst -- drei Zeilen, und die dritte rechnet sich aus
Filipe: "ich will in jeder seite auch eine kleine detaillierte aber
schnelle erklaerung kurz und knapps noch zu jeder seite."
DREI ZEILEN AUF JEDER DER 25 SEITEN
WOFUER was auf dieser Seite steht
DU TUST was man hier konkret macht
MERKE nur dort, wo es etwas gibt, das man falsch versteht
SIEHT wer diese Seite ueberhaupt oeffnen kann
Offen sichtbar und nicht hinter einem Aufklapper: "schnell" war seine
Bedingung, und eine Erklaerung, die man erst aufklappen muss, ist
genau dann nicht da, wenn man sie braucht.
DIE ZEILE "SIEHT" IST GERECHNET, NICHT GESCHRIEBEN
Sie kommt aus der Rechtetafel -- aus derselben, aus der auch die
Schranke ihre Entscheidung holt. Haette ich sie danebengeschrieben,
waere sie beim ersten Umstellen in "Wer sieht was" still falsch
geworden, in einem Satz, der behauptet, wer etwas sieht. Die Pruefung
stellt die Tafel deshalb wirklich um und sieht nach, ob der Satz
mitwandert.
Die Erklaerung haengt hinter derselben Schranke wie die Seite: Wer sie
nicht oeffnen darf, bekommt 404 -- nicht 403, sonst waere dieser Weg
eine Landkarte des Hauses.
Eingebunden ist sie nicht ueber eine Liste von Dateinamen, sondern
ueber "wer kopf.js laedt": die 26. Seite ist damit automatisch dabei.
Fuenf Seiten haben keine Kopfzeile (Chat, Kalender, Start, Team,
Teamlage) -- dort haengt der Kasten an <main>, sonst waeren
ausgerechnet die haeufigsten Seiten lautlos leer geblieben.
ZWEI EIGENE MAENGEL, GEFUNDEN DURCH HINSEHEN, NICHT DURCH DIE PRUEFUNG
Die erste Fassung war gruen -- und stand mitten auf dem Buehnenbild,
mit einem Lichtfleck hinter "SIEHT". Und "Wofuer" sprach fast woertlich
die Unterzeile darueber nach. Beides misst die Pruefung jetzt: Kontrast
mit dem dritten Ausgang ("steht auf der Buehne" ist kein Ergebnis) und
die Wortueberschneidung mit der Unterzeile.
ZWEI BEFUNDE, DIE SCHON VORHER ROT WAREN
1. pruef-tempo-workspace verglich die UNKOMPRIMIERTE Groesse gegen eine
Grenze, die fuer die Leitung gedacht war -- waehrend der Kommentar
daneben "das ist, was wirklich ueber die Leitung ging" behauptete.
Live steht Caddy davor. Nachgemessen an der echten Adresse:
start.css 345 KB -> 111 KB zstd. Die Pruefung wog also 1,2 MB, wo
Filipe 500 KB bekommt. Jetzt wird Komprimierbares im Pruefstand
gzip-gepackt (115 KB gegen 111 KB live -- auf vier Prozent genau),
geurteilt wird ueber die uebertragene Groesse, berichtet werden
beide. Dabei prompt in die dokumentierte Falle getappt: `body()` auf
einen Ereignisstrom endet nie, der Lauf blieb stehen. Jetzt
ausgenommen, plus Notbremse je Koerper.
2. pruef-ueberlappung konnte seit Tagen nicht mehr zeigen, dass sie
eine Ueberlappung ueberhaupt findet: Ihre Gegenprobe legt einen Knopf
auf einen anderen, traf aber 6 px daneben. Zwei Ursachen in einer
Zeile -- `position: fixed` bezieht sich auf einen Vorfahren mit
`transform`, und die `transition` der Knoepfe liefert beim sofortigen
Messen die Lage von vorher. Jetzt `transform` + `transition: none`:
34x36 px erkannt, 20 Seiten-Breiten-Paare, 0 Befunde.
PRUEFUNGEN: pruef-erklaerung neu mit 44, davon 8 im Browser (Seite mit
und ohne Kopfzeile, Handy, Kontrast, Echo). Mein Schild stand auf
10,88 px und lag unter der Hausgrenze von 11,5 -- gefunden von
pruef-css-klassen, nicht vom Auge.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
GEGENPROBE am Ende: eine kuenstlich erzeugte Doppelanfrage und ein
|
||||
kuenstlicher Layout-Sprung muessen gefunden werden. */
|
||||
|
||||
import { gzipSync } from "node:zlib";
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
@@ -153,9 +154,45 @@ await seite.waitForTimeout(600);
|
||||
/* Grenzen. Grosszuegig -- sie sollen den Ausreisser finden, nicht das
|
||||
Kilobyte. */
|
||||
const GRENZE_ANFRAGEN = 40;
|
||||
const GRENZE_BYTES = 1_200_000;
|
||||
const GRENZE_MS = 4000;
|
||||
|
||||
/* ---- DAS GEWICHT: GEMESSEN WIRD, WAS UEBER DIE LEITUNG GEHT ----------
|
||||
|
||||
BIS ZUM 14.09.2026 WURDE HIER DAS FALSCHE GEMESSEN, und der Kommentar
|
||||
daneben behauptete sogar das Richtige („das ist, was wirklich ueber
|
||||
die Leitung ging"). Der Pruefstand spricht mit dem nackten
|
||||
Express-Server auf 127.0.0.1, und der komprimiert nicht. Live steht
|
||||
davor Caddy.
|
||||
|
||||
NACHGEMESSEN an der echten Adresse, nicht vermutet:
|
||||
curl -H 'Accept-Encoding: zstd' workspace.dogfather-universe.com/…
|
||||
start.css 345 KB -> 111 KB (Content-Encoding: zstd)
|
||||
gate.css 120 KB -> 40 KB
|
||||
kopf.js 65 KB -> 24 KB
|
||||
|
||||
Die Prueferei verglich also rund 1,2 MB gegen eine Grenze, die fuer
|
||||
die Leitung gedacht war -- waehrend Filipe rund 500 KB bekommt. Die
|
||||
Folge war eine Warnung, die nichts ueber sein Erlebnis sagt: genau
|
||||
die Sorte, die man nach dreimal Lesen wegklickt.
|
||||
|
||||
JETZT WIRD BEIDES GEMESSEN. Komprimierbares wird im Pruefstand
|
||||
gzip-gepackt (gemessen: start.css 356 KB -> 115 KB gzip gegen 111 KB
|
||||
zstd live -- ein Stellvertreter, der auf vier Prozent genau ist),
|
||||
alles andere zaehlt roh. Geurteilt wird ueber die uebertragene
|
||||
Groesse, berichtet werden beide.
|
||||
|
||||
DIE GRENZE: 900 KB uebertragen. Die schwerste Seite liegt heute bei
|
||||
rund 500 KB, davon 286 KB Buehnenbild -- das ist der Ausreisser, den
|
||||
diese Zahl finden soll, mit Luft fuer eine zweite. Die rohe Groesse
|
||||
bleibt in der Ausgabe stehen: Sie kostet zwar keine Leitung, aber
|
||||
Rechenzeit beim Auswerten, und sie ist die Zahl, die man senken kann. */
|
||||
const GRENZE_UEBERTRAGEN = 900_000;
|
||||
|
||||
/* Was Caddy komprimiert. Bilder, Schriften und Videos sind bereits
|
||||
gepackt -- sie noch einmal durch gzip zu schicken kostet Zeit und
|
||||
spart nichts. */
|
||||
const KOMPRIMIERBAR = /^(text\/|application\/(javascript|json|xml|manifest)|image\/svg)/i;
|
||||
|
||||
/* ---- Layout-Sprung: eine GRUNDLINIE, kein Wunschwert ------------------
|
||||
Gemessen am 04.09.2026 (Audit): Die Seiten springen beim Aufbau
|
||||
zwischen 0 und 0,54. Nach Web Vitals gilt unter 0,1 als gut. Der
|
||||
@@ -175,6 +212,7 @@ const ZIEL_SPRUNG = 0.1; // Web Vitals "gut" -- noch nicht erreicht
|
||||
|
||||
const zeilen = [];
|
||||
let seitenGesamt = 0, anfragenGesamt = 0, bytesGesamt = 0;
|
||||
const nichtGewogen = [];
|
||||
const doppelte = [];
|
||||
const langsame = [];
|
||||
const springende = [];
|
||||
@@ -184,9 +222,34 @@ const zuGross = [];
|
||||
for (const datei of SEITEN) {
|
||||
const gesehen = new Map();
|
||||
let bytes = 0;
|
||||
let roheBytes = 0, uebertragen = 0;
|
||||
const warten = [];
|
||||
const zaehler = (antwort) => {
|
||||
const u = antwort.url();
|
||||
gesehen.set(u, (gesehen.get(u) || 0) + 1);
|
||||
/* Den Koerper JETZT holen -- nach dem Seitenwechsel ist er weg.
|
||||
Ein Fehlschlag (Umleitung, 204, abgebrochen) ist kein Befund,
|
||||
sondern schlicht nichts zu wiegen. */
|
||||
const art = antwort.headers()["content-type"] || "";
|
||||
/* EIN EREIGNISSTROM ENDET NIE -- und `body()` darauf auch nicht.
|
||||
Genau daran ist am 06.09.2026 schon einmal ein ganzer Lauf
|
||||
stehengeblieben, und hier ist es sofort wieder passiert: Der
|
||||
Workspace haelt eine offene Verbindung fuer Benachrichtigungen.
|
||||
Erst gar nicht anfassen -- und fuer alles andere trotzdem eine
|
||||
Notbremse, weil die naechste Sorte Dauerverbindung noch nicht
|
||||
erfunden ist. */
|
||||
if (/event-stream/i.test(art)) return;
|
||||
warten.push((async () => {
|
||||
try {
|
||||
const k = await Promise.race([
|
||||
antwort.body(),
|
||||
new Promise((r) => setTimeout(() => r(null), 3000)),
|
||||
]);
|
||||
if (!k?.length) return;
|
||||
roheBytes += k.length;
|
||||
uebertragen += KOMPRIMIERBAR.test(art) ? gzipSync(k).length : k.length;
|
||||
} catch { /* nichts zu wiegen */ }
|
||||
})());
|
||||
};
|
||||
seite.on("response", zaehler);
|
||||
|
||||
@@ -195,6 +258,7 @@ for (const datei of SEITEN) {
|
||||
await seite.waitForTimeout(500);
|
||||
const dauer = Date.now() - start;
|
||||
seite.off("response", zaehler);
|
||||
await Promise.all(warten);
|
||||
|
||||
/* Uebertragene Groesse aus der Zeitleiste des Browsers -- das ist,
|
||||
was wirklich ueber die Leitung ging. */
|
||||
@@ -309,12 +373,23 @@ for (const datei of SEITEN) {
|
||||
schwankend.push(`${datei} ${sprung} → beim Nachmessen ${zweitens.wert}`);
|
||||
}
|
||||
}
|
||||
if (anfragen > GRENZE_ANFRAGEN || bytes > GRENZE_BYTES) {
|
||||
zuGross.push(`${datei} ${anfragen} Anfragen / ${Math.round(bytes / 1024)} KB`);
|
||||
/* KONNTE ueberhaupt gewogen werden? Kommt aus den Koerpern nichts
|
||||
zurueck (Browser aus dem Zwischenspeicher, alles abgebrochen),
|
||||
waere „unter der Grenze" trivial wahr. Dann gilt die Zeitleiste
|
||||
des Browsers als Rueckfall -- und der dritte Ausgang steht in der
|
||||
Ausgabe. */
|
||||
const gewogen = uebertragen > 0;
|
||||
const zaehlwert = gewogen ? uebertragen : bytes;
|
||||
if (!gewogen) nichtGewogen.push(datei);
|
||||
|
||||
if (anfragen > GRENZE_ANFRAGEN || zaehlwert > GRENZE_UEBERTRAGEN) {
|
||||
zuGross.push(`${datei} ${anfragen} Anfragen / ${Math.round(zaehlwert / 1024)} KB übertragen`);
|
||||
}
|
||||
|
||||
zeilen.push(` ${datei.padEnd(22)} ${String(anfragen).padStart(3)} Anfragen `
|
||||
+ `${String(Math.round(bytes / 1024)).padStart(4)} KB ${String(dauer).padStart(4)} ms `
|
||||
+ `${String(Math.round(zaehlwert / 1024)).padStart(4)} KB über die Leitung `
|
||||
+ `(roh ${String(Math.round((roheBytes || bytes) / 1024)).padStart(4)}) `
|
||||
+ `${String(dauer).padStart(4)} ms `
|
||||
+ `Sprung ${String(sprung).padStart(5)} ${String(messung.knoten).padStart(4)} Knoten`);
|
||||
}
|
||||
|
||||
@@ -388,7 +463,13 @@ console.log(` hinw ${ueberZiel} von ${seitenGesamt} Seiten liegen ueber dem Z
|
||||
+ `${ZIEL_SPRUNG} fuer den Layout-Sprung (bauartbedingt: Geruest zuerst, Daten danach)`);
|
||||
ok(zuGross.length === 0,
|
||||
zuGross.length ? `zu schwer: ${zuGross.join(", ")}`
|
||||
: `keine Seite ueber ${GRENZE_ANFRAGEN} Anfragen oder ${Math.round(GRENZE_BYTES / 1024)} KB`);
|
||||
: `keine Seite ueber ${GRENZE_ANFRAGEN} Anfragen oder ${Math.round(GRENZE_UEBERTRAGEN / 1024)} KB ueber die Leitung`);
|
||||
/* DER DRITTE AUSGANG: Konnte ueberhaupt gewogen werden? Eine Seite,
|
||||
deren Koerper der Browser aus dem Zwischenspeicher genommen hat,
|
||||
waere sonst lautlos „leicht“. */
|
||||
ok(nichtGewogen.length === 0,
|
||||
nichtGewogen.length ? `KONNTE NICHT WIEGEN: ${nichtGewogen.join(", ")} -- Ergebnis unbrauchbar`
|
||||
: `alle ${seitenGesamt} Seiten wirklich gewogen`);
|
||||
|
||||
/* =======================================================================
|
||||
GEGENPROBE
|
||||
|
||||
Reference in New Issue
Block a user