Zum Inhalt springen
Michael Seel
Zurück

Turbo - dynamische Webapps abseits von SPAs

Abstraktes Titelbild zu Turbo - dynamische Webapps abseits von SPAs

Turbo - dynamische Webapps abseits von SPAs

Im April habe ich beim MunichJS Meetup einen Vortrag über Hotwire Turbo gehalten. Vor einem JavaScript-affinen Publikum, im Hilton Munich City, 30 Minuten über eine Technologie, deren zentrale These lautet: Ihr braucht weniger JavaScript. Das war ein bewusster Kontrapunkt, und die Diskussion danach hat gezeigt, dass das Thema einen Nerv trifft. Dieser Artikel fasst die Kernideen zusammen und geht an einigen Stellen tiefer als der Vortrag es konnte.

Das Problem, das keiner mehr sehen will

Ich baue seit über zehn Jahren SPAs. Große Onlineshops für namhafte Handelsunternehmen, dazu komplexe Unternehmensanwendungen. In jedem dieser Projekte war die Frontend-Architektur ein eigenständiges Gravitationsfeld. Eigene Build-Pipeline, eigene Dependency-Hölle, eigene Versionskonflikte.

Single-Page Applications haben eine Menge Probleme gelöst. Schnelle Interaktionen, flüssige Übergänge, ein App-artiges Gefühl im Browser. Aber sie haben auch eine Menge Probleme mitgebracht:

Das sind keine theoretischen Probleme. Das sind die Realitäten, die ich in Kundenprojekten sehe. Jedes einzelne davon ist lösbar, aber in Summe kauft man sich eine Grundkomplexität ein, die viele Anwendungen schlicht nicht brauchen.

Die Idee: HTML Over The Wire

Turbo dreht die Grundannahme von SPAs um. Statt JSON vom Server zu holen und im Browser mit JavaScript zu rendern, schickt der Server fertiges HTML. Der Browser muss kein JavaScript ausführen um die Seite darzustellen. Er tut das, was er am besten kann: HTML rendern.

Das klingt erstmal wie ein Rückschritt. Zurück zu PHP und jQuery? Nein. Der entscheidende Unterschied: Turbo macht aus klassischen Server-Responses etwas Dynamisches, ohne dass die Seite neu lädt. Das Ergebnis fühlt sich an wie eine SPA, aber die Architektur bleibt serverseitig.

Turbo ist Teil von Hotwire (HTML Over The Wire), entwickelt von 37signals, den Machern von Basecamp und HEY. Seit Rails 7 ist es der Standard-Frontend-Ansatz in Ruby on Rails. Aber Turbo ist framework-agnostisch. Es funktioniert mit jeder serverseitigen Technologie: Node.js, Laravel, Django, Spring Boot, Phoenix. Für meinen Vortrag habe ich eine Demo mit Express und EJS gebaut, bewusst ohne Rails, um zu zeigen, dass Turbo kein Rails-Feature ist.

Turbo Drive: Das unsichtbare Upgrade

Turbo Drive ist die einfachste Komponente und gleichzeitig die mit dem größten sofortigen Effekt. Es fängt jeden Klick auf einen Link und jede Formular-Submission ab, führt die Navigation per Fetch im Hintergrund aus und tauscht nur den <body> der Seite aus. Der <head> bleibt bestehen, JavaScript und CSS werden nicht neu geladen.

<!-- Kein spezielles Markup nötig. Turbo Drive aktiviert sich automatisch. -->
<a href="/dashboard">Dashboard</a>

Das Ergebnis: Jede klassische Multi-Page Application fühlt sich plötzlich schnell an. Kein Full-Page Reload, kein weißer Blitz, kein erneutes Parsen von CSS und JavaScript. Einfach durch das Einbinden von Turbo, ohne eine einzige Zeile Code zu ändern.

Für bestehende Anwendungen ist das ein Geschenk. Man bindet Turbo ein und bekommt sofort spürbar schnellere Navigation. Keine Migration, kein Rewrite.

Turbo Frames: Unabhängige Seitenabschnitte

Turbo Frames gehen einen Schritt weiter. Sie ermöglichen es, einzelne Bereiche einer Seite unabhängig zu laden und zu aktualisieren, ohne den Rest der Seite anzufassen.

<turbo-frame id="notifications">
  <a href="/notifications">Benachrichtigungen laden</a>
</turbo-frame>

Wenn der Nutzer den Link klickt, holt Turbo die Seite /notifications, extrahiert daraus den <turbo-frame> mit der gleichen ID, und ersetzt nur diesen Bereich. Der Rest der Seite bleibt unangetastet.

Das löst ein Problem, für das in der SPA-Welt ganze State-Management-Bibliotheken existieren: Partielle Updates. Ein Kommentarbereich, der sich aktualisiert ohne die Seite neu zu laden. Ein Warenkorb-Widget, das sich nach dem Hinzufügen eines Artikels aktualisiert. Eine Suchleiste mit Live-Ergebnissen. Alles ohne eine Zeile clientseitiges JavaScript.

Frames sind lazy-loadable, navigieren unabhängig voneinander und können auch aus anderen Seiten Inhalte nachladen. Im Prinzip verhalten sie sich wie intelligente iframes, nur semantisch sauber und ohne die Probleme von iframes.

Turbo Streams: Echtzeit vom Server

Turbo Streams sind das mächtigste Feature. Sie erlauben dem Server, gezielte DOM-Manipulationen als HTML-Fragmente zu schicken. Das kann als Antwort auf eine Formular-Submission passieren oder in Echtzeit über WebSockets.

<turbo-stream action="append" target="messages">
  <template>
    <div id="message_42">
      <p>Neue Nachricht vom Server</p>
    </div>
  </template>
</turbo-stream>

Sieben Aktionen stehen zur Verfügung: append, prepend, replace, update, remove, before, after. Damit lassen sich die meisten UI-Updates abbilden, die man in einer reaktiven Anwendung braucht.

Ein Chat? Der Server pusht neue Nachrichten per WebSocket als append-Stream. Ein gelöschter Eintrag? Ein remove-Stream mit der Ziel-ID. Eine aktualisierte Statusanzeige? Ein replace-Stream. Der Browser braucht kein JavaScript um das zu verarbeiten, Turbo übernimmt das.

Was Turbo nicht ist

Turbo ist kein Allheilmittel, und es wäre unehrlich, es als solches darzustellen.

Turbo ersetzt keine hochinteraktiven UIs. Ein Figma, ein Google Maps, ein kollaborativer Code-Editor, das sind Anwendungen die zu Recht auf schwere clientseitige Logik setzen. Turbo ist für die 80% der Webanwendungen, die im Kern CRUD-Operationen auf Daten durchführen und dafür keine 2 MB JavaScript brauchen.

Turbo ersetzt kein clientseitiges JavaScript komplett. Für Interaktionen wie Dropdowns, Validierungen oder Toggles braucht man nach wie vor JS. Aber es sind kleine, isolierte Schnipsel, kein Framework mit eigenem Ökosystem.

Der Trend ist breiter

Turbo steht nicht allein. HTMX verfolgt eine ähnliche Philosophie mit einem anderen API-Design. Phoenix LiveView in Elixir geht noch weiter und hält den State komplett auf dem Server. Selbst React bewegt sich mit Server Components in eine Richtung, die mehr Logik zurück auf den Server bringt.

Das ist kein Zufall. Nach Jahren der SPA-Maximierung findet gerade eine Korrektur statt. Nicht zurück zu 2005, aber hin zu einer nüchternen Bestandsaufnahme: Welche Komplexität ist tatsächlich notwendig? Und welche haben wir uns aus Gewohnheit eingekauft?

In meinen Projekten stelle ich diese Frage jetzt bei jeder Architekturentscheidung. Nicht jede Anwendung braucht React. Nicht jede Anwendung braucht eine API-first-Architektur. Manchmal ist die ehrlichste Antwort: Ein Server der HTML rendert, und ein Browser der es anzeigt. Turbo macht genau das erstaunlich einfach und gleichzeitig interaktiv.


Dieser Artikel basiert auf meinem Vortrag “Turbo - dynamische Webapps abseits von Single-Page Applications” beim MunichJS Meetup am 18. April 2024 im Hilton Munich City. Die Demo-App (Node.js/Express) ist auf GitHub verfügbar.

Live-Demo: Turbo Frames in Aktion



Vorheriger Artikel
Von der Skizze zur iOS-App in eineinhalb Tagen
Nächster Artikel
React und komplexe Architekturen