Startseite / Artikel / Wiederaufnahmefähige Inseln auf Bun: Designlektionen aus dem Stoneware-Framework

Wiederaufnahmefähige Inseln auf Bun: Designlektionen aus dem Stoneware-Framework

Wie ein serverbasiertes Framework HTML als Standard verwendet, JavaScript auf wiederholbar abrufbare Einheiten beschränkt und statische Exporte, Fehler, CSP sowie die Bereitstellung handhabt.

3252 Wörter

Die meisten Webseiten bestehen aus Inhalten, zu denen einige interaktive Steuerelemente hinzugefügt werden, doch das vorherrschende Entwicklungsmodell liefert die gesamte Seite dem Browser als JavaScript-Anwendung. Stoneware, ein junges Open-Source-TypeScript-Framework, das auf Bun basiert, geht von der entgegengesetzten Annahme aus: HTML ist das, was der Browser standardmäßig erhält, und ein Komponent muss sich ausdrücklich dafür entscheiden, bevor JavaScript für sie gesendet wird. Eine Betrachtung seines Designs ist eine nützliche Möglichkeit, Konzepte wie Inselarchitekturen, Wiederaufnahmefähigkeit, statische Exportfunktionen sowie weniger auffällige Aspekte der Framework-Entwicklung wie Fehlermeldungen, Sicherheitsabläufe und Bereitstellungsverpackung zu verstehen. Am Ende sollten Sie in der Lage sein, beurteilen zu können, wann eine serverbasierte, auf Inselarchitekturen gestützte Lösung zu Ihrem Projekt passt und welche Fallstricke bei der Entwicklung oder Einführung einer solchen Architektur zu beachten sind.

Warum eine Inhaltsseite keine Anwendung werden sollte

Stellen Sie sich eine typische Produktseite vor. Sie enthält einen Titel, ein Foto, eine Beschreibung, eine Liste der Spezifikationen, einen Preis, verwandte Produkte, Bewertungen sowie Navigationsmöglichkeiten auf der Seite. Von all dem reagieren vermutlich nur zwei Elemente tatsächlich auf den Benutzer: das Mobile-Menü und die Schaltfläche „In den Warenkorb legen“. Alles Weitere ist statische Inhalte, die der Server bereits kennen muss, um sie bereitzustellen.

Eine clientseitig rendernde oder vollständig hydratisierte Herangehensweise verlangt dennoch von dem Browser, Code herunterzuladen, zu analysieren und auszuführen, der die gesamte Seite darstellt – nur damit diese beiden Steuerelemente funktionieren können. Die serverbasierte Frage ist einfach: Was, wenn der Browser nur den Code für die Teile erhält, die er benötigt?

Das mentale Modell: HTML plus Inseln

Die Architektur teilt eine Seite in zwei Arten von Bereichen auf. Der größte Teil besteht aus serverseitig generiertem HTML. Die interaktiven Elemente bilden Inseln – kleine, selbstständige Bereiche, die ihre eigene JavaScript-Logik enthalten. Beides findet sich schließlich im selben Dokument im Browser wieder.

Web page
                            │
                ┌───────────┴───────────┐
                │                       │
             HTML                    Islands
                │                       │
        Server rendered          JavaScript
                │                       │
                └───────────┬───────────┘
                            │
                         Browser

Die wichtigste Folge ist, dass Interaktivität nicht mehr dazu zwingt, die gesamte Anwendung mitzuliefern. Um ein Widget interaktiv zu machen, muss man lediglich dessen Code bereitstellen, nicht den des gesamten Pages.

Auf Bun aufbauen anstelle einer Toolchain zusammenzustellen

Durch die Wahl von Bun wird nicht behauptet, Node.js sei veraltet. Node verfügt über ein riesiges Ökosystem und wird für einen großen Teil der produktiven JavaScript-Anwendungen eingesetzt; es bleibt weiterhin eine hervorragende Laufzeitumgebung. Interessant ist vielmehr, was sich ändert, wenn ein Framework um eine Laufzeitumgebung konzipiert wird, die bereits die meisten Tools enthält, die Projekte benötigen.

Bun liefert einen JavaScript-Runtime zusammen mit einem Paketmanager, einem Bundler und einem Testlaufwerk. Für Framework-Entwickler bedeutet das eine erhebliche Vereinfachung. Anstatt ein Framework auf Node zu setzen, anschließend einen Paketmanager, dann einen separaten Bundler und schließlich einen separaten Testlaufwerk, kann die Architektur all diese Komponenten als eine zusammenhängende Grundlage betrachten.

Bun
                     │
        ┌────────────┼────────────┐
        │            │            │
      Runtime     Tooling       Testing
        │            │            │
        └────────────┼────────────┘
                     ↓
                 Stoneware

Es ist wichtig, die Rollen klar zu unterscheiden: Bun ist die Plattform, während Stoneware das darauf basierende Framework ist. Für einen umfassenderen Vergleich der Runtimes selbst siehe Node.js, Deno und Bun im Vergleich.

HTML zuerst – ernst genommen

Serverseitiges Rendering gibt es bereits seit langer Zeit, daher klingt „HTML auf dem Server rendern“ unbedeutend. Das stärkere Prinzip hinter Stoneware ist, dass der Server wirklich nützliches HTML erzeugen sollte, bevor der Browser irgendetwas über die Anwendung verstehen muss.

Nehmen wir ein Komponente, das ein Produkt mit Titel und Preis anzeigt.

<ProductCard
  title="MacBook Pro"
  price={1999}
/>

Es gibt nichts an dieser Komponente, was erfordert, dass der Browser ein JavaScript-Modell davon speichert. Der Server kann sie in reine Markup-Strukturen umwandeln:

<div class="product-card">
  <h2>MacBook Pro</h2>
  <span>$1999</span>
</div>

Diese Ausgabe ist bereits vollständig. Menschen können sie lesen, Suchmaschinen-Crawler können sie indizieren, und der Browser kann sie sofort darstellen. Bei der Bereitstellung des Inhalts selbst ist kein Script beteiligt.

JavaScript zu einer expliziten Entscheidung machen

Fügen wir nun einen Warenkorb-Button hinzu. Im Gegensatz zur Produktkarte muss dieser auf Klicks reagieren, den Zustand aktualisieren und vermutlich mit einer API kommunizieren.

<AddToCart product={product} />

Dieser Komponente liegt die Rechtfertigung für das Verhalten auf der Client-Seite zugrunde, wodurch sie zu einer Insel wird. Der Rest der Seite bleibt als HTML erhalten, und die resultierende Seite sieht so aus:

Product page
│
├── Product title          HTML
├── Product description    HTML
├── Product image          HTML
├── Product specifications HTML
│
└── Add to cart            JavaScript island

Die Seite ist nicht „JavaScript-frei“. Sie ist selektiv skriptbasiert, wobei die Auswahl pro Komponente und nicht pro Seite vorgenommen wird. Dieser Unterschied ist wichtig, denn er sorgt dafür, dass die Standardlösung kostengünstig bleibt, und macht jeden im Produkt enthaltenen Code zu einer sichtbaren, bewussten Entscheidung.

Wo die Grenze der Insel liegt

Eine Insel markiert die Grenze zwischen auf dem Server gerendertem Inhalt und auf der Client-Seite ausgeführtem Verhalten. Eine Dokumentationsseite zeigt dieses Muster deutlich. Der Artikeltext, Überschriften, Codebeispiele, Bilder, Links, die Navigation sowie der Fußbereich sind allesamt Inhalt. Nur wenige Funktionen sind wirklich interaktiv: die Suche, ein Theme-Wechsler, Kopieren-in-Clipboard-Buttons in Codeblöcken und möglicherweise ein erweiterbarer Navigationstree.

Documentation page
│
├── Article ─────────────── SSR
├── Code blocks ─────────── SSR
├── Images ──────────────── SSR
├── Navigation ──────────── SSR
│
├── Search ──────────────── Island
├── Theme switcher ──────── Island
└── Copy button ─────────── Island

Genau solche Seiten, hauptsächlich aus Inhalt mit einigen interaktiven Bereichen bestehend, sind das, wofür das Framework konzipiert wurde.

Hydratierung versus Wiederaufnahmemöglichkeit

Ein berechtigter Einwand ist, dass all das lediglich SSR sei. Teils stimmt das: Der Server rendert HTML. Der Unterschied liegt darin, was geschieht, sobald dieses HTML ankommt.

Bei der klassischen Hydratierung verläuft die Abfolge in etwa wie folgt:

  • der Server sendet HTML;
  • der Browser lädt die JavaScript-Dateien der Anwendung herunter;
  • Das Framework führt den Komponentenbaum im Speicher aus und rebuildet ihn;
  • Event-Handler werden dem vorhandenen DOM hinzugefügt.
  • Der Browser rekonstruiert letztendlich eine Anwendung, deren Ausgabe er bereits erhalten hat. Aus Sicht des Benutzers handelt es sich dabei um reine Overhead-Arbeit: Die Pixel waren bereits auf dem Bildschirm.

    Stoneware ist hingegen um wiederholbar startbare Bereiche konzipiert. Der Server sendet HTML zusammen mit dem Zustand, den die interaktiven Bereiche benötigen, und der Browser nimmt dort an, wo der Server aufgehört hat, anstatt die Seite erneut auszuführen, um diesen Zustand neu zu ermitteln. Ziel ist es, zu verhindern, dass kleine interaktive Bereiche eine vollständige Rekonstruktion der Seite erzwingen.

    Ein anderes Optimierungsziel

    Die Möglichkeit zum Wiederaufnehmen verändert die Frage nach der Leistung. Anstatt zu fragen, wie man die Aktualisierung aller Elemente beschleunigen kann, geht es darum, wie viel Browserarbeit man ganz vermeiden kann. Die zu übertragende Datenmenge wechselt von „HTML plus all der JavaScript-Code der Anwendung plus ein Aktualisierungsprozess“ zu „HTML plus nur der für die Interaktion benötigte Code, wobei von dem vom Server bereitgestellten Zustand ausgegangen wird“. Bei inhaltlich reichhaltigen Webseiten ist das oft ein viel größerer Vorteil als jede Optimierung der Aktualisierungsprozesse.

    Falls Sie mit React arbeiten, steht hinter Server Components derselbe Ansatz; die Architektur hinter dem zero-bundle Rendering erläutert diesen Ansatz und bietet einen nützlichen Vergleich.

    Server-first bedeutet nicht nur Server

    Keines davon ist ein Argument gegen Client-Seiten-Anwendungen. Kollaborative Editor, Design-Tools, Browserspiele sowie komplexe interaktive Datenanwendungen haben völlig unterschiedliche Anforderungen, und die meisten ihrer Komponenten sind von Natur aus interaktiv. Die Architektur richtet sich hingegen auf das andere Ende des Spektrums aus: Seiten, bei denen der größte Teil des Inhalts von Natur aus auf dem Server dargestellt wird und Interaktion die Ausnahme darstellt.

    Die statische Exportfunktion folgt derselben Idee

    Falls HTML die Standardoption ist, stellt sich die logische nächste Frage, warum überhaupt ein Server für Seiten benötigt wird, die pro Anfrage niemals ändern. Stoneware kann eine Anwendung als statische Dateien exportieren und sie an ein CDN übergeben.

    Stoneware application
            │
            ▼
         export
            │
            ▼
          dist/
            │
            ▼
           CDN
    

    Dokumentation, Marketingseiten und Produktkataloge können oft im Voraus erstellt und direkt von der Edge-Infrastruktur bereitgestellt werden. Routen, die tatsächlich eine Logik pro Anfrage benötigen, können weiterhin auf dem Server gerendert werden. Der Vorteil ist, dass ein Wechsel einer Route zwischen statischer und SSR-Verarbeitung kein Umschalten auf ein anderes Programmiermodell für die gesamte Anwendung erfordert.

    Dynamische Routen benötigen eine explizite Liste der Pfade

    Die statische Exportierung wird schwieriger, sobald eine Route Parameter enthält. Eine Route wie /products/[sku] könnte im Prinzip unzählige URLs abdecken, wodurch der Exporteur nicht erraten kann, welche Seiten erzeugt werden sollen. Daher bittet das Framework die Route, diese aufzulisten:

    export function staticPaths() {
      return products.map(product => ({
        sku: product.sku
      }));
    }
    

    Mit dieser Liste erstellt der Exporteur für jede bekannte SKU eine echte HTML-Datei, beispielsweise dist/products/laptop-1/index.html. Hier geht die Framework-Entwicklung über das reine Rendern von JSX hinaus: Das Framework muss verstehen, wie Routen, Daten, der Build-Prozess und das Deployment-Ziel miteinander verbunden sind. Ein praktischer Randfall, den man berücksichtigen muss, ist die Situation, in der eine dynamische Route überhaupt keine staticPaths() aufweist; das Framework muss entweder den Export deutlich fehlschlagen lassen oder diese Route serverseitig rendern – sie still wegzulassen ist die schlechteste Option.

    Fehlermeldungen gehören zum Renderer

    Im Kern nimmt ein Renderer eine Komponente entgegen und erzeugt HTML. Die Schwierigkeit liegt in der enormen Vielfalt an Kindkomponenten und Eigenschaften, mit denen er umgehen muss: Text- und Zahlenwerte, Arrays sowie null, Elemente und verschachtelte Komponenten, Signale und Attribute, ausgelöste Fehler, asynchrone Aufgaben – sowie unweigerlich Werte, die nicht dargestellt werden können.

    Ein häufiger Fehler ist es, <span>{product}</span> zu schreiben, obwohl man eigentlich <span>{product.name}</span> meint. Eine allgemeine Meldung wie „Wert vom Typ Object kann nicht dargestellt werden“ sagt fast nichts darüber aus, wo man suchen soll. Stoneware hingegen beschreibt den fehlerhaften Wert detailliert:

    Cannot render a plain object with keys: id, title, price.
    

    und fügt anschließend den Pfad zur betreffenden Komponente hinzu:

    in <span>
    in <Price>
    in <ProductCard>
    in <Home>
    

    Die Auflistung der Schlüssel des Objekts gibt Hinweise auf die Eigenschaft, die Sie wahrscheinlich gemeint haben, und der Komponentenpfad weist auf die genaue Datei hin, die geöffnet werden muss. Ein Framework wird nicht nur anhand seines erfolgreichen Ablaufs beurteilt, sondern auch daran, wie schnell es einem aus schwierigen Situationen hilft.

    Wenn ein Mikrobenchmark die tatsächlichen Kosten versteckt

    Die Erfassung dieses Komponentenpfads bedeutete ursprünglich, viele Renderungsoperationen in try/catch einzubetten. Ein isolierter Mikrobenchmark zeigte an, dass die zusätzlichen Kosten vernachlässigbar seien. Bei einer realistischen Seite-Renderung machte das Einbetten jedes Elements die Renderung jedoch um etwa 38 Prozent teurer.

    Die Erklärung ist jedem bekannt, der JavaScript benchmarkt: In einem kleinen, wiederholten Benchmark kann der optimierende Compiler des Engines einen Großteil der Arbeit, die man messen möchte, entfernen oder verschieben, sodass die erzielten Werte eine optimierte Version des Codes widerspiegeln.

    Mikrobenchmarks können irreführend sein, wenn die Laufzeitumgebung genau das optimiert, was gemessen werden soll.

    Die Lösung war strukturell angelegt. Der Overhead durch Fehlerverfolgung wurde auf die Grenzen der Komponenten beschränkt, und einzelne Elemente nutzten günstigere Speichern- und Wiederherstellungsoperationen, um den Zustand beizubehalten. A/B-Tests an tatsächlichen Darstellungen zeigten anschließend keinen signifikanten Unterschied. Die übergeordnete Lektion ist, dass die Leistung eines Renderers genauso davon abhängt, beim Hinzufügen entwicklerfreundlicher Funktionen keine Rückschritte zu machen, wie von der reinen Geschwindigkeit – und dass jede Leistungsbehauptung anhand repräsentativer Arbeitslasten überprüft werden sollte.

    Sicherheitsstandards und Reihenfolge der Pipeline

    Eine grundlegende Anwendung sollte ihren Entwickler nicht dazu zwingen, sich vor der Veröffentlichung an alle Sicherheitsmechanismen zu erinnern. Stoneware wird mit Standards wie CSRF-Schutz und Unterstützung für Content Security Policy ausgeliefert.

    Die Reihenfolge des Anfragenpipelines ist bewusst gewählt:

    • Zuerst wird der CSRF-Schutz ausgeführt;
    • dann läuft das Anwendungs-Middleware;
    • danach erfolgt die Pfadübereinstimmung und Darstellung;
    • alles verlässt schließlich über einen einzigen Antwortausgang.

    Falls das Anwendungs-Middleware vor der CSRF-Prüfung ausgeführt würde, könnte Benutzercode auf einen Pfad gelangen, der eine Sicherheitsgrenze auf Framework-Ebene umgeht – beispielsweise durch vorzeitige Rückgabe oder Umschreiben der Anfrage. Die Reihenfolge im Framework festzulegen, anstatt sie nur zu dokumentieren und darauf zu hoffen, dass alle sich daran halten, ist genau die Art von Regel, die ein Framework selbst vorgeben sollte. Ein einziger Ausgangspunkt bedeutet außerdem, dass Header wie CSP konsistent auf jede Antwort angewendet werden.

    Eine strenge CSP erweitern, ohne sie deaktivieren zu müssen

    Eine restriktive Richtlinie ist eine gute Standard-Einstellung, doch echte Websites laden Analyse-Tools, Zahlungswidgets, APIs, Web-Schriften und Karten. Der häufige Fehler besteht darin, dass ein Entwickler auf einen blockierten Skript stößt und die CSP vollständig deaktiviert. Ein besseres Design ermöglicht es, einzelne Richtlinien zu erweitern, während der Rest der Standardrichtlinie unverändert bleibt:

    csp: {
      scriptSrc: ["https://www.googletagmanager.com"],
      connectSrc: ["https://www.google-analytics.com"],
      imgSrc: ["https://www.google-analytics.com"],
    }
    

    Das Prinzip besteht aus sicheren Standard-Einstellungen sowie einer expliziten, richtlinienbezogenen Erlaubungsliste für Dritte. Bei der Gestaltung einer solchen API sollte klar entschieden werden, ob eine bereitgestellte Quelle zur Standardrichtlinie hinzukommt oder diese ersetzt, und die Entscheidung dokumentiert werden – schließlich sind beide Verhaltensweisen möglich und haben unterschiedliche Sicherheitsfolgen.

    Die schwierigsten Fehler treten nach dem Renderer auf

    Ein Framework endet nicht beim Renderer. Der Code muss den gesamten Prozess überstehen: Quelle, Compiler, Renderer, Kompilierung, Ressourcen, Bereitstellung, CDN und schließlich der Browser. Einige der hartnäckigsten Probleme treten gegen Ende dieser Kette auf, weit entfernt vom Code, den die meisten Menschen als „das Framework“ betrachten.

    Paketierung von Ressourcen für Vercel

    Die Veröffentlichung 0.1.8 änderte die Art und Weise, wie Stoneware auf Vercel bereitgestellt wird. Für dieses Ziel sind die generierten Client-Blöcke nun als Base64-Daten im Server-Bundle eingebettet, wodurch sie Teil des von der Plattform bereitgestellten Bundles werden und über /_stoneware/* bereitgestellt werden.

    Stoneware build
          ↓
    server bundle
          ├── server code
          ├── CSS assets
          └── island assets
                  ↓
              Vercel
                  ↓
          /_stoneware/*
    

    Dieses Verhalten ist optional und beschränkt sich auf das Vercel-Ziel. Eine Container-Deployment enthält bereits die Dateien auf der Festplatte und hat keinen Grund, eine zweite Kopie jedes Datensatzes im Server-Bundle mitzuführen. Im Großen und Ganzen unterscheiden sich Hosting-Plattformen darin, was sie bei einer Deployment enthalten, weshalb die Handhabung von Ressourcen oft zielbezogene Strategien erfordert anstelle einer universellen Lösung.

    Tests, die eine Korrektur nachweisen

    Das Projekt verfügt über mehr als 500 automatisierte Tests, die den Renderer, den Router, Islands und Signals, Stylesheets sowie die Ressourcenzuweisung, die statische Exportierung, CSRF und CSP, Deployment-Ziele, Fehlerberichterstattung sowie feindliche oder ungewöhnliche Eingaben wie Versuche zur Pfadumgehung, Binärdateien und fehlerhafte Ressourcepfade abdecken.

    Die Anzahl an Tests ist an sich nicht entscheidend. Der nützlichere Maßstab lautet:

    Ein Regressionstest sollte nachweisen, dass er vor der Korrektur fehlgeschlagen wäre.

    Ein Test, der sowohl vor als auch nach einer Änderung bestanden wird, dokumentiert das Verhalten, schützt aber nicht davor, dass der Fehler zurückkehrt. Zu überprüfen, ob ein neuer Test mit dem alten Code fehlschlägt, ist eine günstige Gewohnheit, die einen Testsuite um ein Vielfaches zuverlässiger macht.

    Nutzung eines Programmier-Agenten ohne Auslagerung der Gestaltung

    Ein Großteil von Stoneware wurde mit Claude als Programmier-Agent umgesetzt. Er war besonders effektiv bei der Erforschung einer wachsenden Codebasis, beim Schreiben wiederkehrender Infrastrukturkomponenten, bei der Erstellung von Tests, bei der Analyse von Fehlern, beim Refactoring, bei der Dokumentation der Architektur sowie bei der Prüfung von Randfällen.

    Was er allein nicht tun konnte, war zu entscheiden, welches Framework verwendet werden sollte. Die schwierigen Fragen betrafen die Architektur:

    • Für jeden Pfad – ist SSR oder statische Exportierung der richtige Modus?
  • Wie sollte die Exportfunktion bei einer dynamischen Route ohne staticPaths() funktionieren?
  • Wie sollte der Renderer reagieren, wenn eine Komponente ein einfaches Objekt zurückgibt?
  • Welche Orte durchsucht der Build, um Stylesheets zu finden?
  • Wie erreichen die generierten Client-Chunks den Browser auf Vercel?
  • Fügt eine vom Entwickler bereitgestellte CSP-Quelle zur Standardrichtlinie hinzu oder überschreibt sie diese?
  • Ein Entwickler kann sich mit diesen Fragen auseinandersetzen und eine gewählte Lösung umsetzen, doch jemand muss den Entwurf weiterhin überprüfen und das Ergebnis validieren.

    Plausibel ist nicht dasselbe wie richtig

    Ein Programmieragent kann eine überzeugende Implementierung sehr schnell erstellen, und diese Geschwindigkeit ist wertvoll. Gleichzeitig bedeutet das jedoch auch, dass er schnell Fehler machen kann. Das Problem mit den Vercel-Ressourcen veranschaulicht diesen Kreislauf: Die erste Korrektur kopierte die generierten Ressourcen in public/, was sinnvoll erschien und die lokalen Tests bestand; eine tatsächliche Bereitstellung zeigte jedoch, dass diese Annahme falsch war. Der zweite Versuch änderte das Bereitstellungsmodell selbst. Tests für Randfälle enthüllten anschließend einen weiteren Fehler in dieser Version.

    Dieser Zyklus ist typisch für die Softwareentwicklung – kein Versagen der KI. Was sich ändert, ist die Geschwindigkeit jeder Iteration, wodurch eine End-to-End-Überprüfung in der echten Zielumgebung noch wichtiger wird, anstatt weniger.

    Warum die Wahl des Laufzeitumfelds mehr bedeutet als nur Geschwindigkeit

    Die Geschichte auf „Bun ist schneller als Node“ zu reduzieren, würde den Kernpunkt verfehlen – schließlich ist reine Geschwindigkeit ohnehin keine Philosophie eines Frameworks. Das interessantere Experiment besteht darin, ein Framework unter der Annahme zu entwerfen, dass ab dem ersten Tag bereits eine moderne Laufzeitumgebung sowie ein integrierter Toolchain zur Verfügung stehen. Buns Kombination aus Laufzeitumgebung, Paketverwaltung, Bundling und Testing macht es zu einer praktischen Grundlage für solche architektonischen Erkundungen.

    Wo die Architektur passt

    Der Ansatz kommt besonders gut zur Geltung, wenn der größte Teil einer Seite aus Inhalten besteht und nur ein Teil interaktiv ist:

    • Dokumentation: Artikel und Codebeispiele werden auf dem Server gerendert; Suchfunktion, Themenswitcher und Kopieren-Buttons sind eigenständige Elemente.
    • E-Commerce: Produktdetails, Bilder und SEO-Inhalte werden auf dem Server gerendert; Warenkorb und Filter sind eigenständige Elemente.
  • Unternehmenswebseiten: Firmeninformationen, Dienstleistungen und Märkte werden auf dem Server generiert; das Kontaktformular ist entweder eine eigenständige Einheit oder erfordert eine Serverinteraktion.
  • Inhaltsseiten: Die Artikel werden auf dem Server generiert; Kommentare und Suchfunktionen sind eigenständige Einheiten.
  • Wo es wahrscheinlich das falsche Werkzeug ist

    Falls Ihr Produkt im Grunde eine Desktop-Anwendung ist, die in einem Browser läuft – wie beispielsweise ein gemeinsam nutzbarer Editor, ein Grafiktool, ein Spiel, eine stark interaktive Kontrollleiste oder jede Anwendung, bei der fast alle Komponenten auf dem Client laufen – dann ist der Anteil der Seite, der als HTML erhalten bleiben kann, gering. Das Inselmodell fügt somit unnötige Grenzen hinzu, ohne viel Arbeit zu sparen; eine kundenorientierte Architektur eignet sich in solchen Fällen wahrscheinlich besser. Ein Framework kann eine klare Meinung vertreten, ohne vorzutäuschen, dass es für jede Art von Arbeitslast geeignet ist.

    Ausprobieren

    Zum Zeitpunkt der Erstellung befindet sich Stoneware noch in der 0.1.x-Serie, daher sind unvollkommene Aspekte zu erwarten – prüfen Sie den Repository-Status für aktuelle Informationen. Zu den geplanten Verbesserungen gehören mehr Integrationen, bessere Diagnose- und Entwicklungswarnungen, weitere Beispiele sowie Bereitstellungsziele, verbesserte Dokumentation und mehr Anwendungen aus der Praxis. Um ein Projekt aufzubauen und den Entwicklungsserver zu starten:

    bun create stoneware my-app
    cd my-app
    bun dev
    

    Ein gutes erstes Experiment ist etwas Kleines mit viel Inhalt: ein Blog, eine Dokumentationsseite, ein Produktkatalog, ein Portfolio oder eine Unternehmenswebseite. Während Sie daran arbeiten, fragen Sie stets nach, wie viel auf der Seite tatsächlich JavaScript benötigt.

    Haupterkenntnisse

    • Betrachten Sie HTML als Standardausgabe und machen Sie clientseitiges JavaScript zu einer optionalen Funktion pro Komponente; so wird die Seite selektiv skriptiert anstatt als vollständige Anwendung.
  • Durch die Wiederverwendbarkeit ändert sich das Ziel von einer schnelleren Aktualisierung des Inhalts zu einer vollständigen Vermeidung von Arbeit durch den Browser, was insbesondere auf inhaltsschweren Seiten Vorteile bringt.
  • Statische Exportfunktionen und SSR können in einem Programmiermodell zusammenexistieren, doch dynamische Routen erfordern eine explizite Liste der Pfade.
  • Investieren Sie in Fehlermeldungen, die den fehlerhaften Wert sowie den Pfad der Komponente angeben; überprüfen Sie die Leistung anhand realistischer Darstellungen und nicht nur anhand von Mikrobenchmarks.
  • Bringen Sie Sicherheitsmaßnahmen wie CSRF vor Middleware in das Framework ein und ermöglichen Sie Entwicklern, CSP-Anweisungen zu erweitern, anstatt die Richtlinien einfach auszuschalten.
  • Die Zielumgebungen für die Bereitstellung unterscheiden sich; überprüfen Sie die Handhabung der Ressourcen von Anfang bis Ende und schreiben Sie Regressionstests, die ohne die Korrektur fehlschlagen.
  • KI-Agenten beschleunigen die Implementierung, doch architektonische Entscheidungen sowie die Überprüfung in der echten Umgebung bleiben menschliche Verantwortlichkeiten.