{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreih64zaxsh3wovvbutfpzmxwcy42yl5gpl4hyw26qk7dou3lupdrdm",
"uri": "at://did:plc:uuprngwsp3glcn45cadaimqf/app.bsky.feed.post/3mgmu5spokwy2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreicotsgz3zrk6rlw5kgpm6xfl53ogze5o4rj3x42vykckv6zqabkma"
},
"mimeType": "image/jpeg",
"size": 13560
},
"path": "/sechs-sekunden-bis-zur-startseite",
"publishedAt": "2026-03-01T00:00:00.000Z",
"site": "https://hnz.io",
"tags": [
"maschinenraum",
"Staticache"
],
"textContent": "Manchmal merkt man erst, wie langsam eine Website geworden ist, wenn man sie selbst aufruft und plötzlich Zeit hat, sich einen Kaffee zu holen.\n\nGenau so ging es mir mit meiner Seite hier: Die Startseite brauchte plötzlich bis zu sechs Sekunden, bis überhaupt etwas passierte. Um mich nicht falsch zu verstehen: bis der erste HTML-Response kam. Danach liefen CSS, JavaScript und Bilder völlig normal durch. Das Problem lag also ziemlich offensichtlich vor dem Browser, irgendwo auf dem Server.\n\nSechs Sekunden sind nicht nur für einen Androiden, sondern generell im Web eine Ewigkeit. Also habe ich mir Chatty dazugeholt, um mir beim Debuggen zu helfen.\n\nDie Ausgangslage war schnell klar: Der erste Request auf hnz.io/ hing. Danach ging alles zügig weiter. Das spricht meistens dafür, dass der Server beim Rendern der Seite lange beschäftigt ist.\n\nMein erster Reflex war die klassische Performance-Lösung: Caching.\n\n## Der erste Versuch: Staticache\n\nKirby hat von Haus aus schon ein Caching-Modul an Board, ich habe mich aber zusätzlich noch für Staticache entschieden. Das berechnet im ebsten Fall eine Seite bis zur nächsten Änderung einmal vor und gibt dann die Vorberrechnete Version an die Browser weiter.\n\nZusätzlich habe ich die gzip-Komprimierung eingeschaltet. Gzip ist eine Technik, mit der Textantworten wie HTML oder CSS kleiner gemacht werden, bevor sie übertragen werden. Das spart Bandbreite und beschleunigt die Übertragung.\n\nDer erste Test brachte allerdings eine kleine Überraschung: Die Startseite brauchte immer noch mehrere Sekunden.\n\n## Wenn Caching nicht hilft\n\nDas war der Punkt, an dem klar wurde, dass der Cache gar nicht das eigentliche Problem löst.\n\nWenn eine Seite trotz Cache mehrere Sekunden braucht, dann passiert eines von zwei Dingen:\n\n * Entweder der Request landet gar nicht im Cache.\n * Oder der Request muss trotzdem noch viel dynamische Logik ausführen.\n\n\n\nRaten bringt an dieser Stelle nichts. Also haben Chatty und ich angefangen zu messen.\n\n## Ein kleiner Performance-Schalter\n\nIch wollte eine möglichst leichte Lösung, etwas, das direkt auf dem Server mitläuft und nur dann aktiv ist, wenn ich es brauche und habe ich einen kleinen Schalter eingebaut.\n\nWenn man die Seite mit ?perf=1 aufruft und eingeloggt ist, schreibt die Anwendung Performance-Daten in ein Log. Zusätzlich erscheinen Timing-Informationen im HTTP-Header, die ich dann im Browser anzeigen kann.\n\nGemessen wurden drei Dinge:\n\n * Bootstrap: der Start von PHP und Kirby\n * Renderzeit: das eigentliche Erzeugen der HTML-Seite\n * Gesamtzeit: alles zusammen\n\n\n\nZusätzlich habe ich kleine Marker eingebaut, mit denen man bestimmte Stellen im Code messen kann. Wenn ein Snippet oder eine Funktion auffällig langsam ist, taucht sie im Log sofort auf.\n\nDas Ganze ist im Grunde ein sehr einfacher Profiler. Nicht besonders elegant, aber extrem hilfreich.\n\n## Die Spur führt ins Rendering\n\nDie Messungen zeigten ziemlich eindeutig, wo die Zeit verloren ging und zwar, und das hat mir ungemein geholfen, nich im Netzwerk, DNS oder im TLS-Handshakke. Die ganze Zeit ging für das PHP-Rendering der Seite drauf: Der Server war mehrere Sekunden damit beschäftigt, die Startseite zu berechnen, bevor überhaupt etwas an den Browser geschickt wurde.\n\nDamit war klar, dass wir uns meine Templates und Snippets anschauen müssen. War ja irgendwie auch klar.\n\nIn Kirby sind Snippets kleine wiederverwendbare Template-Blöcke. Man kann sie sich wie Komponenten vorstellen, die HTML generieren.\n\n## Viele kleine Verzögerungen\n\nDie Logs zeigten ein interessantes Muster: Der heftigste Block war die Liste der Beiträge auf der Startseite. Das Snippet, das die Feed-Karten erzeugt, brauchte mehrere Sekunden.\n\nInnerhalb dieses Blocks tauchten immer wieder ähnliche Zeitwerte auf. Viele einzelne Schritte lagen jeweils bei ungefähr 300 Millisekunden.\n\nDas klingt erstmal nicht dramatisch, aber wenn ein Feed zehn Beiträge hat und jeder Beitrag mehrere solcher Schritte ausführt, summiert sich das schnell auf mehrere Sekunden.\n\nEin Beispiel waren Social-Links aus dem IndieConnector. Dabei handelt es sich um Funktionen, die automatisch prüfen, ob ein Beitrag auf Mastodon oder Bluesky veröffentlicht wurde und welche URL dazu gehört. Die hatte ich mal auf die Schnelle eingebaut. Und nun ja.\n\nMan sollte nichts auf die Schnelle einbauen.\n\nNiemals.\n\nZwar ist die Auflösung auf einer Detailseite völlig okay. Im Feed bedeutet sie aber, dass dieselben Informationen mehrfach berechnet werden.\n\nDazu kamen kleine Dinge wie Bild-Fallbacks oder Kommentarzählungen, die ebenfalls für jeden Beitrag erneut ausgeführt wurden. Teilweise mehrfach.\n\n## Der entscheidende Schritt\n\nDie Lösung bestand letztlich darin, zwei verschiedene Kontexte sauber zu trennen: Die Startseite ist ein Listing. Sie zeigt viele Beiträge gleichzeitig. In diesem Kontext muss alles möglichst leichtgewichtig sein.\n\nEine Detailseite dagegen zeigt nur einen einzigen Beitrag. Dort kann man sich mehr Rechenzeit leisten.\n\nAlso habe ich einige Funktionen im Feed bewusst abgeschaltet oder vereinfacht.\n\n * Social-Links werden im Listing nicht mehr komplett aufgelöst.\n * Kommentarzahlen greifen auf bereits berechnete Metriken zurück.\n * Einige Bildlogiken wurden reduziert.\n\n\n\nDie Detailseiten behalten weiterhin die vollständige Funktionalität.\n\nDas Ergebnis ist eine klare Trennung: Der Feed bleibt schnell, während Detailseiten alle Informationen anzeigen.\n\nUnd Chatty hat dabei geholfen, die kritischen Stellen zu identifizieren und die Messungen sauber auszuwerten.\n\n## Ein kleiner Nebeneffekt\n\nWährend wir ohnehin am Feed gearbeitet haben, habe ich auch die Bildgrößen angepasst.\n\nDie Startseite lädt jetzt kleinere Vorschaubilder. Große Originale werden erst geladen, wenn man sie tatsächlich öffnet.\n\nDas reduziert Bandbreite und sorgt dafür, dass der Browser weniger Arbeit beim Layout hat. Der eigentliche Performance-Gewinn kam aber weiterhin vom Server.\n\n## Was ich aus der Geschichte gelernt habe\n\nDie wichtigste Lektion ist überraschend simpel:\n\n * Performanceprobleme löst man nicht durch Rumratwn, sondern durch Messungen Und die Spurensuche hat echt Spaß gemacht, war mein erstes Mal.\n * Caching ist hilfreich, aber kein Allheilmittel. Wenn der Flaschenhals im Rendering liegt, muss man verstehen, was genau dort passiert.\n * Oft sind es nicht große, offensichtliche Probleme, sondern viele kleine Kosten pro Eintrag.\n * Baue niemals auf die schnelle irgendetwas ein, ohne dir vorher Gedanken zu machen oder es zumindest zu testen.\n\n",
"title": "Sechs Sekunden bis zur Startseite"
}