Ein praktischer Blick auf den Compiler-Ansatz für Web-Performance: Gegenüberstellung von runtime-lastigen Frameworks und Compile-Time-Ausgaben plus ein einfaches Entscheidungsmodell.

Nutzer beschreiben Performance selten technisch. Sie sagen, die App fühlt sich schwer an. Seiten brauchen einen Moment, bis etwas sichtbar ist, Buttons reagieren verspätet, und einfache Aktionen wie das Öffnen eines Menüs, Tippen in ein Suchfeld oder das Wechseln von Tabs ruckeln.
Die Symptome sind vertraut: ein langsamer erster Ladevorgang (leere oder halb aufgebaute UI), träges Interagieren (Klicks landen nach einer Pause, ruckeliges Scrollen) und lange Spinner nach Aktionen, die sofort wirken sollten, wie das Speichern eines Formulars oder das Filtern einer Liste.
Viel davon sind Laufzeitkosten. Einfach gesagt: die Arbeit, die der Browser nach dem Laden der Seite leisten muss, damit die App nutzbar wird: mehr JavaScript herunterladen, parsen, ausführen, die UI aufbauen, Handler anhängen und dann bei jedem Update weiterarbeiten. Selbst auf schnellen Geräten gibt es eine Grenze, wie viel JavaScript man dem Browser zumuten kann, bevor die Erfahrung beginnt zu leiden.
Performance-Probleme treten oft erst später auf. Anfangs ist die App klein: ein paar Bildschirme, leichte Daten, einfache UI. Dann wächst das Produkt. Marketing fügt Tracker hinzu, Design reichere Komponenten, Teams fügen State, Features, Abhängigkeiten und Personalisierung hinzu. Jede Änderung wirkt für sich harmlos, aber die Gesamtarbeit summiert sich.
Deshalb beginnen Teams, Compiler-first Performance-Ideen ernst zu nehmen. Das Ziel ist selten perfekte Scores, sondern weiter liefern zu können, ohne dass die App jeden Monat langsamer wird.
Die meisten Frontend-Frameworks helfen beim Bauen einer App und dabei, die UI mit Daten synchron zu halten. Der entscheidende Unterschied ist, wann der zweite Teil passiert.
Bei einem runtime-lastigen Framework passiert mehr Arbeit im Browser nach dem Laden der Seite. Du lieferst eine universelle Runtime, die viele Fälle abdecken kann: Änderungen verfolgen, entscheiden, was aktualisiert werden muss, und diese Aktualisierungen anwenden. Diese Flexibilität ist in der Entwicklung großartig, bedeutet aber oft mehr JavaScript, das heruntergeladen, geparst und ausgeführt werden muss, bevor die UI bereit erscheint.
Bei Compile-Time-Optimierung verlagert sich mehr Arbeit in den Build-Schritt. Statt dem Browser ein großes Regelwerk zu schicken, analysiert das Build-Tool deine Komponenten und erzeugt direkteren, an die App angepassten Code.
Ein nützliches Bild:
Die meisten echten Produkte liegen irgendwo dazwischen. Compiler-first-Ansätze liefern immer noch etwas Runtime-Code (Routing, Datenabruf, Animationen, Fehlerbehandlung). Runtime-lastige Frameworks nutzen ebenfalls Build-Time-Techniken (Minifizierung, Code-Splitting, Server-Rendering), um die Arbeit im Client zu reduzieren. Die praktische Frage ist nicht, welche Seite „richtig“ ist, sondern welche Mischung zu deinem Produkt passt.
Rich Harris ist eine der klarsten Stimmen hinter compiler-first Frontend-Denkweisen. Sein Argument ist pragmatisch: Mach mehr Arbeit vorab, damit Nutzer weniger Code herunterladen und der Browser weniger Arbeit hat.
Die Motivation ist praktisch. Viele runtime-lastige Frameworks liefern eine General-Purpose-Engine: Komponentenlogik, Reaktivität, Diffing, Scheduling und Helfer, die für jede mögliche App funktionieren müssen. Diese Flexibilität kostet Bytes und CPU. Selbst bei einer kleinen UI zahlst du für eine große Runtime.
Ein Compiler-Ansatz dreht das Modell um. Zur Build-Zeit schaut der Compiler deine echten Komponenten an und erzeugt den spezifischen DOM-Update-Code, den sie brauchen. Wenn ein Label nie ändert, wird es zu einfachem HTML. Ändert sich nur ein Wert, wird nur der Update-Pfad für diesen Wert ausgegeben. Statt eine generische UI-Maschine auszuliefern, lieferst du das Ergebnis, das auf dein Produkt zugeschnitten ist.
Das führt häufig zu einem einfachen Ergebnis: weniger Framework-Code für die Nutzer und weniger Arbeit bei jeder Interaktion. Es zeigt sich besonders auf Low-End-Geräten, wo zusätzlicher Laufzeit-Overhead schnell spürbar wird.
Tradeoffs bleiben relevant:
Eine praktische Faustregel: Wenn deine UI größtenteils zur Build-Zeit bekannt ist, kann ein Compiler engen Output erzeugen. Ist die UI sehr dynamisch oder plugin-getrieben, kann eine schwerere Runtime einfacher sein.
Compile-Time-Optimierung verändert, wo die Arbeit passiert. Mehr Entscheidungen werden beim Build getroffen, und weniger Arbeit bleibt dem Browser.
Ein sichtbares Ergebnis ist weniger verschicktes JavaScript. Kleinere Bundles reduzieren Netzwerkzeit, Parse-Zeit und die Verzögerung, bevor die Seite auf Tippen oder Klicken reagieren kann. Auf Mittelklasse-Telefonen macht das mehr aus, als viele Teams erwarten.
Compiler können auch direktere DOM-Updates erzeugen. Wenn der Build die Struktur einer Komponente sehen kann, erzeugt er Update-Code, der nur die DOM-Knoten berührt, die sich wirklich ändern, ohne bei jeder Interaktion viele Abstraktionsschichten. Das macht häufige Updates spürbar flüssiger, besonders in Listen, Tabellen und Formularen.
Build-Time-Analyse kann auch Tree-Shaking und Dead-Code-Removal stärken. Der Nutzen ist nicht nur kleinere Dateien, sondern weniger Codepfade, die der Browser laden und ausführen muss.
Hydration ist ein weiterer Bereich, in dem Build-Time-Entscheidungen helfen können. Hydration ist der Schritt, in dem eine server-gerenderte Seite interaktiv wird, indem Event-Handler angebracht und ausreichend Zustand im Browser rekonstruiert wird. Wenn der Build markieren kann, was interaktiv sein muss und was nicht, kannst du die Arbeit beim ersten Laden reduzieren.
Als Nebeneffekt verbessert Kompilierung oft das CSS-Scoping. Der Build kann Klassennamen umschreiben, ungenutzte Styles entfernen und Stil-Leaks zwischen Komponenten reduzieren. Das senkt unerwartete Kosten, wenn die UI wächst.
Stell dir ein Dashboard mit Filtern und einer großen Datentabelle vor. Ein Compiler-first-Ansatz kann den Initial-Load leichter halten, nur die Zellen aktualisieren, die sich nach einem Filterklick ändern, und Teile der Seite vermeiden zu hydrieren, die nie interaktiv werden.
Eine größere Runtime ist nicht automatisch schlecht. Sie kauft oft Flexibilität: Muster, die zur Laufzeit entschieden werden, viele Third-Party-Komponenten und Workflows, die über Jahre getestet sind.
Runtime-lastige Frameworks glänzen, wenn sich die UI-Regeln oft ändern. Wenn du komplexes Routing, verschachtelte Layouts, reichhaltige Formulare und ein tiefes State-Modell brauchst, kann eine ausgereifte Runtime wie ein Sicherheitsnetz wirken.
Eine Runtime hilft, wenn du willst, dass das Framework viel während der Laufzeit übernimmt, nicht nur beim Bauen. Das kann Teams täglich schneller machen, auch wenn es Overhead hinzufügt.
Typische Gewinne sind ein großes Ökosystem, vertraute Muster für State und Datenabruf, starke Dev-Tools, einfachere Plugin-Style-Erweiterung und glatteres Onboarding beim Hiring aus einem bekannten Talent-Pool.
Team-Vertrautheit ist ein echter Kosten- und Nutzenfaktor. Ein etwas langsameres Framework, mit dem dein Team schnell liefern kann, kann ein schnelleres, aber unbekannteres Setup schlagen, das Umschulung, strengere Disziplin oder spezielles Tooling braucht.
Viele Beschwerden über „langsame Apps“ werden nicht durch die Framework-Runtime verursacht. Wenn deine Seite auf eine langsame API wartet, schwere Bilder, zu viele Fonts oder Dritt-Anbieter-Skripte, hilft ein Frameworkwechsel nicht.
Ein internes Admin-Dashboard hinter Login fühlt sich oft in Ordnung an, selbst mit einer größeren Runtime, weil die Nutzer starke Geräte haben und die Arbeit von Tabellen, Berechtigungen und Backend-Queries dominiert wird.
„Schnell genug“ kann am Anfang das richtige Ziel sein. Wenn du noch Produktwert beweist, halte die Iterationsgeschwindigkeit hoch, setze einfache Budgets und nimm compiler-first Komplexität nur an, wenn du Belege hast, dass es nötig ist.
Iterationsgeschwindigkeit ist Time-to-Feedback: wie schnell jemand einen Bildschirm ändern, ausführen, sehen, was kaputt ist, und es beheben kann. Teams, die diese Schleife kurz halten, liefern öfter und lernen schneller. Deshalb fühlen sich runtime-lastige Frameworks anfangs produktiv an: vertraute Muster, schnelle Ergebnisse, viel eingebautes Verhalten.
Performance-Arbeit verlangsamt diese Schleife, wenn sie zu früh oder zu breit betrieben wird. Wenn jeder Pull-Request zu Mikro-Optimierungs-Debatten wird, hört das Team auf, Risiken einzugehen. Wenn du eine komplexe Pipeline baust, bevor du weißt, was das Produkt sein wird, kämpfen Leute mit Tooling statt mit Nutzern.
Der Trick ist, sich auf ein „gut genug“ zu einigen und innerhalb dieses Rahmens zu iterieren. Ein Performance-Budget gibt dir diesen Rahmen. Es geht nicht um perfekte Scores, sondern um Grenzen, die die Erfahrung schützen und trotzdem Entwicklung ermöglichen.
Ein praktisches Budget könnte beinhalten:
Wenn du Performance ignorierst, bezahlst du meist später. Wenn ein Produkt wächst, wird Langsamkeit an Architekturentscheidungen gebunden, nicht nur an kleine Anpassungen. Ein später Rewrite kann bedeuten, Features einzufrieren, das Team umzuschulen und Workflows zu brechen, die zuvor funktionierten.
Compiler-first Tooling kann diesen Kompromiss verschieben. Du akzeptierst vielleicht längere Builds, verringerst aber die Arbeit, die auf jedem Gerät und bei jedem Besuch geleistet werden muss.
Überarbeite Budgets, wenn das Produkt sich bewährt. Schütze anfangs die Grundlagen. Wenn Traffic und Umsatz wachsen, straffe die Budgets und investiere dort, wo Änderungen echte Metriken bewegen, nicht nur Eitelkeit.
Performance-Debatten werden chaotisch, wenn niemand zustimmt, was „schnell“ bedeutet. Wähle ein kleines Set an Metriken, schreibe sie auf und behandle sie als gemeinsame Anzeigetafel.
Ein einfacher Starter-Satz:
Messe auf repräsentativen Geräten, nicht nur auf einem Entwickler-Laptop. Schnelle CPU, warmer Cache und lokaler Server können Verzögerungen verbergen, die auf einem Mittelklasse-Handy über durchschnittliches Mobilnetz sichtbar werden.
Bleib bodenständig: wähle zwei oder drei Geräte, die echten Nutzern entsprechen, und führe denselben Flow jedes Mal aus (Startbildschirm, Login, eine häufige Aufgabe). Mach das konsistent.
Bevor du Frameworks wechselst, nimm eine Basislinie auf. Messe den heutigen Build, protokolliere die Zahlen für dieselben Flows und halte sie sichtbar. Das ist dein Vorher-Foto.
Beurteile Performance nicht nach einem einzelnen Lab-Score. Lab-Tools helfen, können aber das Falsche belohnen (große Verbesserung der ersten Ladung), während sie das vermissen, worüber Nutzer klagen (ruckelige Menüs, langsames Tippen, Verzögerungen nach dem ersten Bildschirm).
Wenn Zahlen schlechter werden, rate nicht. Prüfe, was ausgeliefert wurde, was das Rendering blockiert hat und wo Zeit verbraucht wurde: Netzwerk, JavaScript oder API.
Um eine ruhige, wiederholbare Wahl zu treffen, behandle Framework- und Rendering-Entscheidungen wie Produktentscheidungen. Ziel ist nicht die beste Technik, sondern das richtige Gleichgewicht zwischen Performance und dem Tempo, das dein Team braucht.
Eine Thin Slice sollte die unangenehmen Teile enthalten: reale Daten, Auth und deinen langsamsten Bildschirm.
Wenn du schnell so eine Thin Slice prototypen willst, kann Koder.ai (koder.ai) dir helfen, Web-, Backend- und Mobile-Flows per Chat zu bauen und den Quellcode zu exportieren. Das erlaubt frühe Tests und hält Experimente reversibel mit Snapshots und Rollbacks.
Dokumentiere die Entscheidung in einfacher Sprache, inklusive was dich dazu bringen würde, sie zu überdenken (Traffic-Wachstum, Anteile auf Mobilgeräten, SEO-Ziele). So bleibt die Wahl haltbar, wenn das Team wechselt.
Performance-Entscheidungen gehen meist schief, wenn Teams das optimieren, was sie heute sehen, statt das, was Nutzer in drei Monaten fühlen werden.
Ein Fehler ist Über-Optimierung in Woche eins. Ein Team verbringt Tage damit, Millisekunden von einer Seite zu schaben, die sich noch täglich ändert, während das echte Problem ist, dass Nutzer noch nicht die richtigen Features haben. Beschleunige zuerst das Lernen. Vertiefte Performance-Arbeit kommt, wenn Routen und Komponenten stabil sind.
Ein anderer Fehler ist, das Bundle-Wachstum zu ignorieren, bis es schmerzt. Bei 200 KB fühlt sich alles gut an, dann addieren sich ein paar „kleine“ Ergänzungen und plötzlich verschickst du Megabytes. Eine einfache Gewohnheit hilft: Verfolge die Bundle-Größe über die Zeit und behandle plötzliche Sprünge wie Bugs.
Teams rendern auch standardmäßig alles client-seitig, selbst wenn einige Routen größtenteils statisch sind (Pricing-Seiten, Docs, Onboarding). Solche Seiten lassen sich oft mit viel weniger Arbeit auf dem Gerät ausliefern.
Ein leiser Killer ist, eine große UI-Bibliothek aus Bequemlichkeit hinzuzufügen, ohne ihre Kosten im Produktions-Build zu messen. Bequemlichkeit ist valide. Sei dir nur bewusst, was du in zusätzlichem JavaScript, CSS und langsameren Interaktionen auf Mittelklasse-Handys bezahlst.
Schließlich erzeugt das Mischen von Ansätzen ohne klare Grenzen schwer zu debuggende Apps. Wenn die eine Hälfte der App compiler-generierte Updates erwartet und die andere auf Runtime-Magie baut, endest du mit unklaren Regeln und verwirrenden Fehlern.
Ein paar Guardrails, die in echten Teams halten:
Stell dir ein 3-Personen-Team vor, das eine SaaS für Planung und Abrechnung baut. Es hat zwei Gesichter: eine öffentliche Marketing-Seite (Landing, Pricing, Docs) und ein authentifiziertes Dashboard (Kalender, Rechnungen, Reports, Einstellungen).
Mit einem runtime-first Pfad wählen sie ein runtime-lastiges Setup, weil UI-Änderungen so schnell gehen. Das Dashboard wird zu einer großen client-seitigen App mit wiederverwendbaren Komponenten, einer State-Bibliothek und reichen Interaktionen. Die Iteration ist schnell. Mit der Zeit fühlt sich der First-Load auf Mittelklasse-Handys schwer an.
Mit einem compiler-first Pfad wählen sie ein Framework, das mehr Arbeit in die Build-Zeit verschiebt, um Client-JavaScript zu reduzieren. Häufige Flows wie Dashboard-Öffnen, Tabs wechseln und Suchen fühlen sich reaktiver an. Der Kompromiss ist, dass das Team disziplinierter bei Mustern und Tooling sein muss und einige Runtime-Tricks nicht so einfach per Drop-in funktionieren.
Was eine Änderung auslöst, ist selten Geschmack. Meist kommt der Druck aus der Realität: langsamere Seiten schaden Signups, mehr Nutzer kommen auf Low-End-Geräten, Enterprise-Käufer verlangen vorhersehbare Budgets, das Dashboard ist dauerhaft offen und Speicher wird wichtig, oder Support-Tickets nennen Langsamkeit auf realen Netzen.
Oft gewinnt eine Hybrid-Option. Halte Marketing-Seiten schlank (server-gerendert oder größtenteils statisch, minimales Client-Code) und akzeptiere mehr Runtime im Dashboard, wo Interaktivität sich auszahlt.
Mit den Entscheidungsschritten: sie benennen kritische Journeys (Signup, erste Rechnung, Wochenreport), messen sie auf einem Mittelklasse-Handy, setzen ein Budget und wählen Hybrid. Compiler-first-Default für öffentliche Seiten und gemeinsame Komponenten, runtime-heavy nur dort, wo es die Experimentier-Geschwindigkeit klar verbessert.
Der einfachste Weg, diese Ideen real zu machen, ist ein kurzer wöchentlicher Loop.
Starte mit einem 15-Minuten-Scan: steigt die Bundle-Größe, welche Routen fühlen sich langsam an, welche UI-Teile dominieren diese Routen (Tabellen, Charts, Editoren, Karten) und welche Abhängigkeiten wiegen am meisten. Dann wähle einen Flaschenhals, den du ohne Rewrite beheben kannst.
Für diese Woche halte es klein:
Um Entscheidungen reversibel zu halten, zeichne klare Grenzen zwischen Routen und Features. Bevorzuge Module, die du später austauschen kannst (Charts, Rich-Text-Editoren, Analytics-SDKs), ohne die ganze App anzufassen.
Meistens liegt es nicht nur am Netzwerk, sondern an den Laufzeitkosten: dem Herunterladen, Parsen und Ausführen von JavaScript, dem Aufbau der UI und zusätzlicher Arbeit bei jedem Update.
Deshalb kann eine App selbst auf einem schnellen Laptop „schwer“ wirken, sobald die JavaScript-Arbeit groß wird.
Beide Ansätze verfolgen dasselbe Ziel (weniger Arbeit auf dem Client), sie unterscheiden sich aber im Mechanismus.
Es bedeutet, dass das Framework deine Komponenten zur Build-Zeit analysieren und maßgeschneiderten Code für deine Anwendung ausgeben kann, anstatt eine große generische UI-Engine auszuliefern.
Der praktische Vorteil sind meist kleinere Bundles und weniger CPU-Arbeit bei Interaktionen (Klicks, Tippen, Scrollen).
Beginne mit:
Messe auf repräsentativen Geräten und immer denselben Nutzerfluss, damit Builds vergleichbar sind.
Ja—aber nur wenn die Ursache tatsächlich im Framework liegt. Wenn das Problem langsame APIs, große Bilder, viele Fonts oder Third-Party-Skripte sind, hilft ein Frameworkwechsel nicht.
Behandle die Framework-Wahl als einen Hebel unter mehreren. Prüfe zuerst, wo die Zeit tatsächlich hingeht: Netzwerk, JavaScript-CPU, Rendering oder Backend.
Wähle runtime-lastig, wenn du Flexibilität und schnelle Iteration brauchst:
Wenn der Runtime-Overhead nicht der Engpass ist, kann die Bequemlichkeit die zusätzlichen Bytes wert sein.
Eine einfache Faustregel:
Hybrid funktioniert am besten, wenn du Grenzen schriftlich festhältst, damit die App nicht zu einem unklaren Mix wird.
Nutze ein Budget, das das Gefühl der Nutzer schützt, ohne das Ausliefern zu blockieren. Beispielsweise:
Budgets sind Leitplanken, kein Wettlauf zu perfekten Scores.
Hydration ist die Arbeit, eine server-gerenderte Seite interaktiv zu machen, indem Event-Handler angebracht und genug Zustand im Browser wieder aufgebaut werden.
Wenn du zu viel hydratisierst, kann die erste Ladung langsam wirken, selbst wenn das HTML schnell sichtbar ist. Build-Time-Tools können manchmal reduzieren, was wirklich Interaktivität braucht.
Eine gute Thin-Slice-Probe sollte die echten Schwierigkeiten enthalten:
Wenn du das prototypst, kann Koder.ai (koder.ai) helfen, Web- und Backend-Flow per Chat zu bauen und den Quellcode zu exportieren, damit du messen und Ansätze früh vergleichen kannst, ohne dich vollständig festzulegen.