ReferenzWerkzeugeWachsendaktualisiert 2026.085 Min. Lesezeit
Referenz · Werkzeuge

Die Prüfungen

Ein grüner Build heißt nicht, dass die Seiten in Ordnung sind. Diese Werkzeugkette stellt an jede Schicht eine Prüfung, und jede fängt eine eigene Klasse der stillen Fehler nach dem Muster „Build grün, Seite kaputt“ – zwei von ihnen betrachten Seiten außerdem so, wie ein Leser es tut: in einem echten Browser.

fünf Prüfungen · drei aus der Engine, zwei aus diesem Paket · alles grün vor einem Commit

§1Fünf Schranken, fünf Schichten

PrüfungKommt mitSchaut aufWann ausführen
check-contentEngine, scripts/check-content.mjsjede md/mdx-QuelldateiCI des Inhalts-Repos, oder nach dem Schreiben
check-wikilinksEngine, scripts/check-wikilinks.mjsden [[Wikilink]]-GraphenCI des Inhalts-Repos, oder nach dem Umbenennen einer Notiz
check-distEngine, scripts/check-dist.mjsdie Ausgabe von astro buildnach jedem Build (postbuild)
ui_probedieses Paket, scripts/ui_probe.mjsSeiten, gerendert in einem echten Browsernach Style- und Layoutänderungen
contrast_probedieses Paket, scripts/contrast_probe.mjsden Kontrast jedes Textknotens, beide Themesnach jeder Token-Änderung

§2check-content: die Quelltextschicht

Kompiliert jede md/mdx, die eine Seite werden soll, mit exakt demselben Dialekt wie die Site – Syntaxfehler und stille Verformungen (Hervorhebungsmarken ohne Paar, von der MDX-Auswertung verschluckte Klammern, aus Zeilenumbrüchen geborene Listenmarken, einzeiliges $$, Formeln, die KaTeX nicht rendern kann – dieselbe Liste, mit der Das volle Programm schließt) machen die CI allesamt rot.

Warum dieses Skript aus der Engine kommen muss: Ein Prüfer, dessen Plugin-Satz von dem der Site abweicht, ist schlimmer als gar kein Prüfer – einer ohne Mathe-Plugin liest Formelklammern als JSX-Ausdrücke, einer ohne GFM winkt Tabellen durch. Der Dialekt wird einmal geschrieben, in der Engine; Site-Rendering, Speicher-Validierung des CMS und dieses Skript konsumieren immer denselben.

Wurzel des Inhalts-Repos
node <engine>/scripts/check-content.mjs . --glob '**/index.{md,mdx}' --math

Über das Kompilieren hinaus fängt es zwei Frontmatter-Klassen stillen Verlusts: ein unzitiertes # in einem Wert (YAML liest es als Kommentar und schneidet den Rest stumm ab) und YAML, das gar nicht parst – gemeldet mit Zeilennummer.

Tote [[Wikilinks]] lassen den Build mit Absicht nicht scheitern – ein Garten muss auf Notizen verlinken dürfen, die noch nicht gewachsen sind. In die CI gehört Linkfäule trotzdem, also liefert die Engine einen Lint mit, der jeden Wikilink mit dem Parser und den Auflösungsregeln der Bibliothek selbst auflöst (Alias, Brand, Titel, Locale-Spiegel) und die fehlenden, die mehrdeutigen und die zweifelhaften Anker meldet. --strict macht aus toten Links einen scheiternden Exit – genau so führt die CI dieses Repositorys ihn aus:

der Link-Check dieses Gartens, wie ihn die CI ausführt
node scripts/check-links.mjs

§4check-dist: die Ausgabeschicht

Im gebauten dist/ muss jede interne Referenz, die ein Leser anklicken kann, auch wirklich existieren. Die Prüfung fängt die stillen Lücken unter einem grünen Build:

  • interne Links und Assets auf Dateien, die es nicht gibt (die Sorte, die nach einem Routen-Umbau dutzendweise auftaucht);
  • Seitenanker auf ids, die es nicht gibt;
  • verdoppelte Locale-Segmente in Pfaden (/en/en/ – das klassische Ergebnis von i18n-Fallbacks, die ein Präfix auf schon präfixierte Routen stapeln);
  • <a> in <a> verschachtelt (der HTML-Parser schließt das äußere vorzeitig, und Buttons fallen aus ihren Karten);
  • KaTeX-Fehlerreste (die Formel steht als roter Text auf der Seite, während der Build grün bleibt).

Diese Demo hängt die Prüfung in den Postbuild: Ein grünes npm run build heißt, auch die Ausgabeprüfung hat bestanden.

Site-Wurzel, nach einem Build (deployt die Site unter einem Unterpfad, gib --base mit)
node vendor/astro-inkbrush/scripts/check-dist.mjs dist --base ${DEMO_BASE:-/}

§5Die Render-Probe

Quelltext und Ausgabe können beide stimmen, und die Seite ist trotzdem kaputt – der Klassiker sind Startseitenkarten, auf die keine Stylesheet-Regel mehr passt und die als eine einzige gequetschte Zeile nackten Texts rendern: Link- und Ankerprüfungen bleiben grün, weil sie nie eine gerenderte Seite ansehen. ui_probe fährt einen echten Browser über jede Seite in dist, bei vier Viewport-Breiten (1440/1024/768/430), und misst: horizontales Überlaufen der Seite, Elemente breiter als ihr Container ohne Scrollbox, in der sie wohnen könnten, Klassen, die keine Stylesheet-Regel stylt, übersprungene Überschriftenebenen, doppelte ids, Bilder ohne alt-Attribut, Seitenanker und aria-controls, die ins Leere zeigen. Gemeldet wird nur, was eine Maschine beweisen kann – kein ästhetisches Urteil.

braucht ein lokales Chrome/Chromium
npm run build
node ../scripts/ui_probe.mjs dist   # serviert dist selbst; übergib eine baseUrl, um einen laufenden Server zu proben

Untersucht wird das ganze Dokument – Chrome, Seitenleiste und Dialoge eingeschlossen. Grün heißt, die letzte Zeile des Berichts lautet SAMPLES WITH FINDINGS: 0 (ein Sample ist eine Route bei einer Breite).

§6Die Kontrastprobe

Die Tokens behaupten AA, also wird die Behauptung gemessen statt beteuert. contrast_probe lädt jede Seite aus dist in einem echten Browser – helles und dunkles Theme, Desktop- und Handybreite – und vermisst jeden Textlauf, der im Default-Zustand rendert: HTML-Text, SVG-Text und den generierten Text von ::before / ::after, wobei auf einer repräsentativen Seite jedes <dialog data-probe-open>-Overlay geöffnet geprobt wird (samt einer Suchanfrage, die in ein dort gefundenes Suchfeld getippt wird) – die Marke ist die Erklärung der Site, dass der Dialog fertig verfasst ist. Der Grund wird nicht aus einem Stylesheet gelesen: Die Seite wird mit durchweg transparent gestellten Glyphen gerendert und geschossen, und das Pixel unter jedem Lauf ist sein Grund – Verläufe, color-mix()-Tönungen, durchscheinende Schichten und die Nachtpalette werden also so gemessen, wie sie rendern. Der Vordergrund eines Laufs trägt die akkumulierte opacity seines Elements und seiner Vorfahren, gedimmter Text wird also in der Stärke gemessen, die ein Leser wirklich sieht. Hover- und Fokuszustände werden begutachtet, nicht geprobt. Kleintext muss 4.5:1 halten, großer Text (24px, oder 18.66px fett) 3:1; ein Lauf, dessen Farbe sich nicht parsen oder dessen Grund sich nicht sampeln lässt, zählt als Befund. Der Bericht nennt Seite, Theme, Breite, Selektor, die beiden Farben und das Verhältnis für jeden Lauf unter der Latte:

nach einem Build, beide Themes
node ../scripts/contrast_probe.mjs dist   # PROBE_THEMES / PROBE_WIDTHS engen die Matrix ein

Die Routine bei Style-Änderungen
Jede Änderung an den Stylesheets oder Komponenten des Pakets geht zuerst durch den Build dieser Demo, dann über die Ausgabe durch ui_probe und contrast_probe – alles grün, bevor committet wird. Die Demo ist zugleich der Prüfstand des Pakets.

Titel, Abschnitte und Fließtext, in dieser Sprache.
    ↑↓ · Enter · Escastro-inkstone