Wie diese Website gebaut ist: statisch, wo es geht, streamend, wo es muss
Diese Website ist auch ein Referenzprojekt. Sie hat drei Sprachen, Dutzende Seiten, mehr als ein Dutzend interaktive Tools und einen KI-Guide, der antwortet, während er schreibt. Sie erreicht in allen vier Lighthouse-Kategorien auf dem Handy 100 und läuft auf den Gratis-Stufen von Azure Static Web Apps und der Gemini-API. Nichts davon braucht einen exotischen Stack: React, Vite, ein Prerender-Schritt und eine Handvoll Prüfungen, die nichts Kaputtes ausliefern. So greifen die Teile ineinander, inklusive zweier Dinge, die ich erst durch Messen herausgefunden habe.
10 Min. Lesezeit
1. Eine Datenquelle, viele Ausgaben
Artikel, Leistungsseiten, Projekte und Tools liegen als typisierte Daten im Repository, eine Datei pro Artikel und pro Leistung. Der Build macht daraus alles, was Lesende oder Maschinen brauchen: die Seiten selbst, einen Index für Listen, eine Sitemap mit allen drei Sprachversionen jeder URL, einen RSS-Feed pro Sprache, ein Teilen-Bild pro Artikel und Sprache, die llms.txt-Zusammenfassung für KI-Assistenten und die Wissensdatei, aus der der KI-Guide antwortet.
Die letzten beiden wurden früher von Hand gepflegt und liefen beim ersten Produkt-Umbenennen auseinander. Jetzt erzeugt ein Skript sie bei jedem Build aus denselben Daten neu, und eine Prüfung schlägt fehl, wenn die eingecheckte Fassung nicht passt. Nichts wird doppelt geschrieben, also kann sich nichts widersprechen.
// package.json
"build": "node scripts/gen-posts-meta.mjs && node scripts/gen-knowledge.mjs
&& tsc --noEmit -p tsconfig.app.json && vite build
&& node scripts/sitemap.mjs && node scripts/prerender.mjs"2. Jede Seite vorrendern, in jeder Sprache
Die Website ist eine React-App, aber niemand lädt eine leere Hülle. Nach dem Vite-Build startet ein Skript die gebaute Website lokal, öffnet jede Route in jeder Sprache in einem Headless-Chrome und speichert das fertige HTML in eine eigene Datei: jede Seite mal drei Sprachen. Jede hat eigenen Titel, eigene Beschreibung, kanonische URL, hreflang-Links auf die anderen beiden Sprachen und strukturierte Daten für Artikel, FAQs und Breadcrumbs. Derselbe Lauf erstellt pro Artikel ein Teilen-Bild.
Sprachen stecken im Pfad: Englisch im Root, Deutsch unter /de, Spanisch unter /es. Azure Static Web Apps liefert jede vorgerenderte Datei direkt über Rewrite-Regeln aus, die der Build erzeugt, und eine Sperre lässt den Build fehlschlagen, wenn zwei Regeln kollidieren, was einmal mit /de und /de/ passiert ist. Für Crawler ist das gewöhnliches statisches HTML; für Menschen übernimmt die React-App, und jeder weitere Klick ist sofort da.
3. Den ersten Paint nicht verschenken
Drei Messungen haben den Code verändert. Erstens wurden deutsch- und spanischsprachige Besucher auf der Startseite erst nach dem 150 KB grossen Haupt-Bundle nach /de oder /es weitergeleitet, was auf dem Handy eine Sekunde kostete. Die Weiterleitung läuft jetzt als zehnzeiliges Inline-Skript ganz oben im HTML. Die Content Security Policy erlaubt genau dieses Skript über seinen SHA-256-Hash, und der Build schlägt fehl, wenn Skript und Hash auseinanderlaufen.
Zweitens ersetzte React die vorgerenderte Seite durch einen leeren Platzhalter, bis der Code-Chunk der Seite ankam, also blinkte der Inhalt, und Lighthouse zählte den zweiten Paint. Jetzt lädt der Browser diesen Chunk, bei Artikeln auch den Artikel selbst, bevor React startet, und das vorgerenderte HTML bleibt stehen, bis React dasselbe anzeigt. Drittens sprang die Webschrift nach dem ersten Paint ein und verschob den Text. Mit vorgeladener Schrift und font-display optional ist sie entweder rechtzeitig da oder wird für diesen Besuch nicht genutzt. Zusammen senkte das den grössten Paint auf dem Handy auf der Startseite von etwa 2,5 auf 1,1 Sekunden.
<!-- index.html: runs before CSS, fonts and the app bundle -->
<script>
(function () {
var l = location, p = l.pathname, s = new URLSearchParams(l.search), q = s.get("lang"), w;
if (/^\/(de|es)(\/|$)/.test(p)) return;
var ok = function (x) { return x === "en" || x === "de" || x === "es"; };
try { w = ok(q) ? q : p === "/" ? [localStorage.getItem("dominik-lang"), (navigator.language || "").slice(0, 2)].filter(ok)[0] : ""; } catch (e) {}
if (w !== "de" && w !== "es") return;
s.delete("lang");
var r = s.toString();
l.replace("/" + w + (p === "/" ? "" : p) + (r ? "?" + r : "") + l.hash);
})();
</script>
<!-- staticwebapp.config.json: script-src 'self' 'sha256-…' -->4. Ein KI-Guide, der auf einem statischen Host streamt
Der Guide unten rechts ist meine eigene Chat-Engine, die hinter dem Produkt Helptempo: eine Web-Komponente im Shadow DOM, damit das CSS der Website sie nicht zerschiessen kann, und ein Server-Handler, der auf jedem Host läuft. Auf dieser Website läuft der Handler als verwaltete Azure Function. Er antwortet aus der generierten Wissensdatei plus den Überschriften der Seite, auf der die Besucherin gerade ist, mit Gemini 3.5 Flash und Gemini 3.5 Flash-Lite als Rückfall, der nur einspringt, bevor das erste Wort gesendet ist. Vorbereitete Antworten machen die vorgeschlagenen Einstiegsfragen sofort, und ein Limit pro Besucher hält den Gratis-Key am Leben.
Fürs Streaming brauchte es das Programmiermodell v4 von Azure Functions mit eingeschalteten HTTP-Streams. Die Überraschung war ein einziger Header: Mit Content-Type 'text/event-stream; charset=utf-8' hielt Azure Static Web Apps die ganze Antwort zurück, bis sie fertig war; mit genau 'text/event-stream' kam jedes Stück an, sobald es geschrieben war. Ich habe das mit acht Varianten auf einer Preview-Umgebung eingegrenzt, bevor ich die Produktion angefasst habe. Jetzt erscheinen die ersten Worte nach etwa 1,2 bis 1,5 Sekunden statt der ganzen Antwort nach 2,5 bis 3.
// api/chat/index.js — Azure Functions v4 on Static Web Apps
const { app } = require("@azure/functions");
app.setup({ enableHttpStream: true });
app.http("chat", { methods: ["GET", "POST"], authLevel: "anonymous", route: "chat",
handler: async (req) => (await chat).azureFunctions(req) });
// in the engine: exactly this content type, no charset suffix
// "Content-Type": "text/event-stream"5. Prüfungen, die das Ausliefern verweigern
Jeder Push auf main baut die Website, prüft die Typen und führt End-to-End-Tests gegen die gebauten Dateien aus, bevor irgendetwas ausgeliefert wird: Jede Route in jeder Sprache muss in Handy- und Desktop-Breite genau ein h1, kein horizontales Scrollen, keine kaputten Bilder und keine Konsolenfehler haben. Der Fragebogen, der Sprachwechsel, geteilte Tool-Links und der Startablauf haben eigene Prüfungen, darunter eine, die das JavaScript ausbremst und fehlschlägt, sobald die vorgerenderte Überschrift verschwindet. Die Chat-API hat eigene Prüfungen, und das Wissen des KI-Guides wird gegen 30 Besucherfragen mit Fakten getestet, die er sagen muss und nicht sagen darf.
Nach dem Deploy meldet die Website über IndexNow, welche URLs sich geändert haben. Ausserhalb der Deploys prüft ein geplanter Job jede Stunde, dass alle Seiten, Artikel, Leitfaden-PDFs, Feeds und der Chat antworten, und ein wöchentlicher Job prüft jeden Quellenlink und jedes Video in den Artikeln. Ein kaputter Link oder eine tote Seite färbt einen Workflow rot und landet in meinem Postfach, bevor ein Besucher darüber stolpert.
6. Was es kostet, und was ich wiederverwenden würde
Gehostet wird im Free-Plan von Azure Static Web Apps mit seinen verwalteten Functions, und der Guide läuft auf einem Gratis-Gemini-Key mit Rückfallmodell, die laufenden Kosten liegen also nahe null. Die Kompromisse sind ehrliche: Das Gratis-Kontingent des Modells ist tagsüber manchmal aufgebraucht und das Rückfallmodell antwortet, und ein statischer Host heisst, dass das Kontaktformular an einen Formulardienst sendet statt an ein eigenes Backend.
Was ich für jede Firmenwebsite wiederverwenden würde: vorrendern statt Server-Rendering, wenn sich Inhalte ein paar Mal am Tag ändern, jede maschinenlesbare Datei aus einer Datenquelle erzeugen, messen vor dem Optimieren und die Pipeline das Ausliefern verweigern lassen, statt darauf zu bauen, dass Menschen an die Prüfungen denken. Die Chat-Engine ist von Grund auf wiederverwendbar; deshalb ist sie ein Produkt geworden.
Fazit
Eine schnelle, mehrsprachige Website mit Live-KI-Guide braucht keine Serverfarm: alles vorrendern, den ersten Paint schützen, nur streamen, was streamen muss, und die Pipeline Nein sagen lassen.
Quellen und offizielle Leitfäden
Weitere Artikel
- 3'025 Pull Requests in zehn Monaten: ein KI-gestützter Delivery-Prozess von innen
- Der EU AI Act für den Mittelstand: was für Sie gilt, und ab wann
- FinOps für KI-Kosten: Tokens, Caching, Routing und Budgets, die halten
- Ein Restaurant-Netzwerk in KI-Antworten sichtbar machen: ein GEO-Projekt Schritt für Schritt
- Kubernetes-Kosten auf EKS und GKE: dasselbe Playbook, andere Hebel
- Eine Landing Zone für den Mittelstand, in Terraform oder Bicep: die Teile, die zählen
- Das Playbook für Legacy-Migrationen: Wellen, Parallelbetrieb und identische Zeilenzahlen und Prüfsummen
- MCP-Sicherheit im Detail: KI-Assistenten ins Produkt lassen, ohne die Türen zu öffnen
- Monitoring auf Geschäftsergebnisse: grüne Dashboards, leere Kasse
- KI-Agenten am Telefon: die Architektur, und die Stolperfallen, die keine Demo zeigt
- Restore-Tests: Ein Backup, das nie wiederhergestellt wurde, ist nur eine Hoffnung
- KI-Antworten auf Azure Static Web Apps streamen: der eine Header, der alles zurückhielt
- Einen KI-Assistenten für WhatsApp bauen, von Anfang bis Ende: was es über die Demo hinaus braucht
- Air-gapped-Systeme: kritische Software ganz ohne Internet betreiben
- Produktive KI auf AWS: Amazon Bedrock und AgentCore in einem privaten Setup
- Produktive KI auf Microsoft Foundry: ein privates Referenz-Setup für Agenten
- /goal, /loop oder Routines: Hören Sie auf, Ihren Coding-Agenten zu babysitten
- Claudes neue Pläne: Max, Ultra und was sie für Teams bedeuten
- OpenAI Codex Ende 2026: Goal Mode, Dots und wie man es absichert
- GitHub Copilot, Claude Code oder Codex? So würde ich für ein Unternehmen entscheiden
- GEO-Grundlagen: So erscheinen Sie in KI-Antworten
- Produktive KI auf Google Cloud: von Vertex AI zur Gemini Enterprise Agent Platform
- Lokale LLMs im Air-Gap-Netz: KI für Ihre sensibelsten Daten
- Ich will ein lokales LLM betreiben: Welchen Server soll ich kaufen?
- MiniMax M3: ein offenes Spitzenmodell zum Selbstbetreiben?
- Prompt-Research im grossen Stil mit einem offenen Modell
- SEO und GEO zusammen: ein praktisches Audit in 6 Schritten
- Kubernetes richtig dimensionieren: das Playbook, mit dem ein Cluster von 7 auf 4 Nodes kam
- Private KI für sensible Daten: ein lokales LLM-Setup, das durch die Sicherheitsprüfung kommt
- Vom KI-Prototyp zur Produktion: die acht Schichten, die ich ergänze, in dieser Reihenfolge
