Startseite / Artikel / Auf Upgrade zu htmx 4: Fetch, explizite Vererbung und was dabei kaputtgeht

Auf Upgrade zu htmx 4: Fetch, explizite Vererbung und was dabei kaputtgeht

Verstehen Sie die Architekturänderungen von htmx 4 – vom auf Fetch basierenden Kern und der expliziten Attributvererbung über Fehlerumschaltungen, Morphing und Historie – und planen Sie eine sichere Migration.

2717 Wörter

Htmx basiert auf einer einfachen, bewusst unmodernen Strategie: Der Server gibt HTML zurück, der Browser fügt dieses HTML in die Seite ein, und es entsteht eine leistungsstarke Anwendung, ohne dass die gesamte Benutzeroberfläche als Client-Seiten-Zustand abgebildet wird. Version 4 behält diese Strategie bei, während die zugrundeliegenden Mechanismen anhand moderner Browser-Primitiven neu aufgebaut werden. Diese Anleitung erläutert, was sich geändert hat und warum, welche Änderungen eine bestehende Anwendung stillschweigend beschädigen können und wie man den Upgrade-Prozess als strukturierte Überprüfung statt als einfaches Versionshochfahren durchführt. Die Details beziehen sich auf htmx 4 wie es zum Zeitpunkt der Erstellung dokumentiert war; überprüfen Sie die genauen Angaben vor dem Migrieren gegen die aktuellen Release-Notes.

Der Vertrag, den htmx 4 bewahrt

Es hilft, sich daran zu erinnern, was htmx ersetzt. Eine typische clientseitig renderierte Anwendung fragt eine API nach JSON, speichert diese Daten in JavaScript, rendert daraus Komponenten und synchronisiert ständig den lokalen Zustand mit dem Server. htmx eliminiert den größten Teil dieser Zwischenschicht. Der Server antwortet mit der Darstellung, die der Benutzer tatsächlich benötigt – nämlich HTML.

Betrachten wir einen Button mit Attributen wie hx-post, ein Ziel wie #task-list sowie eine Einfügestrategie. Wenn jemand darauf klickt, sammelt htmx den Anfragedatenkontext, sendet ihn an den Server, parset die zurückgegebene Markup-Struktur und fügt diese dem Aufgabenverzeichnis hinzu. Validierung, Autorisierung, Persistenz und Darstellung bleiben beim Server. Interaktion, Navigation, Fokussierung sowie das Dokument selbst verbleiben im Browser.

Das ist mehr als nur eine knappe Bezeichnung für fetch(). Die Attribute beschreiben eine Hypermediensteuerung: welche Aktionen verfügbar sind, wohin sie gesendet werden und wie die resultierende Darstellung auf die aktuelle Seite gelangen soll. Der zurückgegebene Fragment kann selbst Links und Formulare enthalten, die auf weitere gültige Aktionen hinweisen – genauso wie eine vollständige Seite. Mit anderen Worten bleibt HTML das Anwendungsprotokoll; htmx koordiniert lediglich den Hin- und Rückweg.

Version 4 lässt diese öffentliche Oberfläche nahezu langweilig stabil. Was neu organisiert wird, ist der Lebenszyklus dahinter. Das Ergebnis ist kein neues Frontend-Framework, sondern strengere Regeln dafür, wie HTML, HTTP, der DOM und der state-basierte Server zusammenarbeiten.

Ein Kern, der auf dem Fetch API aufgebaut ist

Frühere Versionen setzten auf XMLHttpRequest. Das machte Sinn, als htmx in älteren Browsern laufen musste und XHR Upload-Progress-Ereignisse bereitstellte, auf die einige Anwendungen angewiesen waren. Im Laufe der Zeit verwandelte sich diese Kompatibilitätsentscheidung jedoch in strukturellen Verpflichtungen. Das htmx-Team schrieb den Anfragenweg um und nutzte stattdessen die auf Versprechen basierende Fetch-API, wobei es sich von Experimenten mit einem kleineren Projekt namens Fixi sowie vom Streaming von HTML inspirieren ließ.

Ein vorhersehbares Namensschema für Ereignisse

Dieser klarere Ablauf zeigt sich im Ereignismodell. Die Namen der Ereignisse folgen nun einem einheitlichen Muster, htmx:phase:action, das optional durch eine Unteraktion erweitert werden kann (htmx:phase:action:sub-action). Da die Phase zuerst kommt, lässt sich auf einen Blick erkennen, ob ein Listener vor oder nach dem von ihm bezeichneten Schritt ausgelöst wird.

Jedes mit Anfragen verbundene Ereignis erhält ebenfalls dasselbe Kontextobjekt. Erweiterungen und Zuhörer müssen nicht mehr verschiedene, ereignisbezogene Details zusammensuchen, um das Quellelement, die Anfragenkonfiguration, die Antwort sowie den ausstehenden Austausch zu finden – alles befindet sich an einem Ort. Zudem verfügen Anfragen über eine finally-Phase, die unabhängig vom Ergebnis – Erfolg, Misserfolg oder Abbruch – ausgelöst wird. Das ist der ideale Ort für Aufräumarbeiten wie das Verbergen von Ladeindikatoren oder das Wiederaktivieren von Schaltflächen.

Falls Ihre Codebasis htmx-Ereignisse nach Namen abhört, muss jeder Zuhörer überprüft werden, da die alten Namen nicht mehr mit dem neuen Schema übereinstimmen.

In Platform-Elemente umgewandelte Wrapper

Htmx 4 entfernt außerdem Hilfsfunktionen, die APIs duplizierten, die Browser inzwischen zuverlässig bereitstellen:

  • htmx.addClass() wird durch element.classList.add() ersetzt
  • htmx.closest() wird durch element.closest() ersetzt
  • htmx.remove() wird durch element.remove() ersetzt
  • Das ist eine gesunde Weiterentwicklung. Eine kleine Bibliothek sollte keine Convenience-APIs dauerhaft beibehalten, sobald die Plattform sie bereits übernommen hat – schließlich handelt es sich bei den Ersatzlösungen um Standard-DOM-Aufrufe, die jeder Entwickler bereits kennt.

    Attributvererbung ist nun optional

    Die bedeutendste Änderung durch die Migration hat nichts mit Fetch zu tun. Htmx 4 beendet die implizite Vererbung der meisten Attribute von Voreltern-Elementen.

    Zuvor galt ein auf einen Container gesetztes Attribut – beispielsweise ein Ziel, eine Bestätigungsanfrage oder eine Reihe von Anfragesystemen – stillschweigend für alle von htmx gesteuerten Nachkommen. In Version 4 muss man diesen Einfluss explizit deklarieren, indem man dem Attributnamen im Elternelement das Suffix :inherited hinzufügt. Ein Nachkomme, der einen vererbbaren Wert oder Selektor erweitern statt ihn zu überschreiben, kann das Suffix :append verwenden.

    Dieses Suffix dient nicht der Dekoration. Es macht jedem, der das Template liest, klar, dass das Attribut des Elternelements absichtlich Teil des Verhaltens seiner Kinder ist. Dadurch rückt htmx weiter in Richtung einer Lokalität des Verhaltens: Je näher eine Deklaration dem Element liegt, das sie betrifft, desto weniger unsichtbaren Kontext muss ein Leser rekonstruieren. Ein gemeinsames Verhalten ist weiterhin möglich; sein Geltungsbereich wird einfach dort angegeben, wo er deklariert wird.

    Warum dies der riskanteste Teil des Updates ist

    Die Änderung führt außerdem zu einem stillen Fehlermodus. Angenommen, ein CSRF-Header wurde bisher immer in einem Layout-Wrapper definiert. Nach dem Update wird die Seite genauso dargestellt wie zuvor, doch Anfragen von Kindenelementen enthalten den Header nicht mehr und werden vom Server abgelehnt. Es scheint zunächst nichts kaputt zu sein, bis jemand ein Formular absendet.

    Htmx bietet einen offiziellen Upgrade-Checker, der Templates und Skripte auf implizite Vererbung, veraltete Ereignisnamen, entfernte Attribute sowie veraltete APIs überprüft. Verwenden Sie seinen Bericht als Ausgangspunkt – nicht als Garantie – und testen Sie anschließend die tatsächlichen Anfragepfade, insbesondere solche, die durch Header, Bestätigungen oder gemeinsame Ziele geschützt sind.

    Fehlerantworten werden austauschbare Fragmente

    In Htmx 2 wurden standardmäßig keine Antworten mit den Statuscodes 4xx oder 5xx umgewechselt. Htmx 4 ändert das: Es wechselt jede HTTP-Antwort außer 204 No Content und 304 Not Modified.

    Falls verschiedene Statuskategorien an unterschiedliche Orte geleitet oder mit anderen Umwandlungsregeln behandelt werden sollen, ermöglicht das neue Attribut hx-status eine Konfiguration pro Statusklasse – beispielsweise das Versenden von Validierungsfehlern in einen eingebetteten Nachrichtenbereich, während Serverfehler in ein Seitenüberschreibungsbanner gelangen.

    Die eigentliche Folge trifft den Server. Jede Fehlerantwort muss nun ein gültiger Fragment für das jeweilige Element sein, das sie erhält. Ein vollständiger Stack-Trace der gesamten Seite oder ein reines JSON-Fehlerobjekt wird unverändert in den DOM eingefügt. Statuscodes behalten für Caches, Protokolle und Clients ihre HTTP-Bedeutung, während der HTML-Körper die Darstellung sowie idealerweise die nächste Aktion enthält, die der Benutzer ausführen kann – beispielsweise ein korrigiertes Formular.

    Aktualisierung mehrerer Bereiche aus einer Antwort

    Eine einzige Serverseitige Operation muss oft mehr ändern als nur das Element, auf das der Benutzer geklickt hat. Das Versenden einer Nachricht kann diese beispielsweise an eine Zeitachse anhängen, die Anzahl der ungelesenen Nachrichten erhöhen und das Paginierungscontrol ersetzen. Htmx bietet bereits seit längerem Lösungen für solche Fälle: In der Antwort als „out-of-band“ markierte Elemente ersetzen entsprechende Elemente an anderer Stelle im Dokument.

    Htmx 4 fügt ein ausdrücklicheres Werkzeug hinzu, nämlich das Element <hx-partial>. Jedes Partial deklariert seine eigene Ziel- und Austauschstrategie, sodass die Antwort als Liste klar benannter Aktualisierungen dargestellt wird.

    Auch die Reihenfolge ist definiert. Zunächst wird die Hauptantwort ausgetauscht; anschließend folgen die Partials sowie Elemente außerhalb des Hauptstroms in der Reihenfolge im Dokument. Dadurch wird gefördert, dass jede Aktualisierung für sich selbst sinnvoll ist, anstatt von Nebeneffekten einer früheren DOM-Änderung in derselben Antwort abhängig zu sein.

    Das führt zu einer leichten Orchestrierung der Antworten. Der Server kann jede sichtbare Folge einer Operation in einer einzigen Antwort beschreiben, anstatt JSON zurückzugeben und den Client-Code damit zu beauftragen, die Felder auf verschiedene Komponenten zu verteilen.

    Austauschverfahren, die den Browserzustand erhalten

    Das Ersetzen von innerHTML ist leicht nachvollziehbar, doch es führt dazu, dass der Browser gespeicherte Zustände verliert. Ein Textfeld kann seine Auswahl verlieren, der Fokus kann wechseln, ein Video kann neu starten und ein benutzerdefiniertes Element kann zerstört und neu erstellt werden – selbst wenn der größte Teil seiner Markup-Struktur unverändert bleibt.

    Htmx 4 stellt innerMorph und outerMorph bereit, zwei Austauschmodi, die auf einer verbesserten Version des Idiomorph-Algorithmus basieren. Anstatt den Zielunterbaum zu verworfen, vergleicht ein Morph die alten und neuen Knoten und wendet die kleinste mögliche Anzahl an Änderungen an. Knoten, die übereinstimmen, behalten ihre Identität sowie damit ihren Fokus, ihre Auswahl, die Wiedergabestelle und ihren internen Zustand bei.

    Morphing ist nicht automatisch die bessere Wahl. Bei einem einfachen Fragment ist ein vollständiger Ersatz oft sicherer und leichter zu debuggen. Morphing lohnt sich, wenn das Ziel Elemente wie aktive Formulareingabefelder, benutzerdefinierte Elemente, Medieninhalte oder Widgets von Drittanbietern enthält, deren Identität wichtig ist. Htmx stellt außerdem Selektoren bereit, um während eines Morphings ganze Knoten oder nur deren Kinder zu überspringen – eine praktische Methode, um stateful Inhalte wie eingebettete Karten oder Rich-Text-Editor zu schützen.

    Das allgemeine Prinzip ist auch außerhalb von htmx zu befolgen: Der Server entscheidet, wie das HTML aussehen soll, und der Browser bewahrt die physischen DOM-Objekte auf, die während des Übergangs erhalten bleiben sollten.

    Streaming findet in Erweiterungen statt, nicht im Kern

    Fetch bietet htmx eine viel bessere Grundlage für gestreamte Antworten, doch der Kern legt kein einheitliches Streaming-Protokoll für alle fest. Stattdessen bringt htmx 4 separate, auf bestimmte Anwendungsfall zugeschnittene Erweiterungen für Server-Sent Events, WebSockets und multipart-Ansichten mit.

    Die Erweiterung für multipart-Ansichten, hx-multipart, versteht Körper im Format multipart/mixed und multipart/parallel. Jeder Teil kann HTML zusammen mit eigenen HX-*-Aktionshäuptern enthalten. Dadurch kann ein Server zunächst einen vorläufigen Ersatz senden und anschließend weitere Abschnitte streamen, sobald die aufwendigen Aufgaben abgeschlossen sind – wobei jeder Abschnitt individuell behandelt wird, und das ohne den Aufbau eines eigenen Client-seitigen Nachrichtenbusses.

    Die Wahl zwischen diesen Optionen hängt von der Struktur des Datenflusses ab:

    • SSE eignet sich für geordnete, einseitige Aktualisierungen, die vom Server aus gesendet werden.
    • WebSockets sind geeignet für echte, zweireihige Kommunikation.
  • Multipart eignet sich für eine einzige HTTP-Operation, die im Laufe der Zeit mehrere Darstellungen liefert.
  • Sie alle fließen in das gleiche Austauschsystem, sodass der Rest Ihrer Markup-Struktur nicht darauf achten muss, welcher Transport einen Fragment geliefert hat.

    Ein einfacheres Erweiterungsmodell

    Durch die Trennung des Streamens vom Kern bleibt dieser klein, während die Erweiterungsgrenzen dadurch leistungsfähiger werden. Erweiterungen in htmx 4 registrieren sich direkt und können in die Phasen Anfrage, Antwort sowie Austausch eingreifen. Man aktiviert eine solche Erweiterung einfach, indem man deren Skript einbindet; das Attribut hx-ext existiert nicht mehr. Falls eine klare Trennung gewünscht ist, ermöglicht die Konfiguration es, festzulegen, welche Erweiterungsnamen auf einer Seite erlaubt sind.

    HCON: eine kompakte Notation für Attributoptionen

    Sobald Attribute weitere Optionen enthielten, benötigte htmx eine Syntax, die weniger störend war als JSON, das in einem Attributwert eingebettet ist. Die Lösung ist HCON, die htmx Configuration Object Notation. Sie unterstützt mit Leerzeichen getrennte Schlüssel-Wert-Paare, einfache Flags als Boolesche Werte, Zahlen, gekennzeichnete Zeichenketten sowie punktierte Schlüssel für die Verknüpfung von Ebenen.

    JSON wird weiterhin akzeptiert, was praktisch ist, wenn ein Server bereits Konfigurationen erzeugt. HCON richtet sich an manuell geschriebene Markup-Strukturen: ausreichend kompakt, um schnell überflogen zu werden, doch strukturiert genug, sodass htmx keinen separaten Parser für jedes Attribut benötigt. Derselbe Notationstyp wird bei Auslösern, Austauschmodifikatoren, Anfruckskonfigurationen, Headern, Werten sowie dem HX-Location-Antwortheader verwendet – daher lohnt es sich, sie einmal zu erlernen, da sie überall Anwendung findet.

    hx-live für den verbleibenden Client-Zustand

    Hypermedia beseitigt nicht jede Form der lokalen Interaktivität. Vor jeder Anfrage öffnet sich ein Dropdown-Menü. Ein Zeichenzähler aktualisiert sich bei jeder Tastenbetätigung. Tab-Elemente, Ansichtswidgets und vorübergehende Auswahlmöglichkeiten sind in der Regel Sache des Browsers.

    Die neue hx-live-Erweiterung kümmert sich mit einer kleinen, auf dem DOM basierenden Skriptierschicht um diese Fälle. Sie bietet einen Abfragen-Hilfsfunktion, Richtungsselector zur Suche nach benachbarten Elementen, DOM-Utilities, asynchrone Hilfsfunktionen, typisierten Zugriff auf Attribute und Datewerte sowie reaktive Bindungen wie :text, :class und :hidden.

    Ihre leitende Regel ist philosophischer Natur: Der DOM dient als Zustandsspeicher. Eine reaktive Ausdrucksweise liest den Zustand aus benachbarten Elementen und aktualisiert die darstellende Oberfläche. Alles, was dauerhaft ist, bleibt beim Server und erreicht die Seite als HTML – genauso wie zuvor.

    Betrachten Sie hx-live als Entlastungsventil für kleine UI-Aufgaben, nicht als Möglichkeit, eine zweite Anwendung im Browser zu entwickeln. Wenden Sie es an, wenn Sie sonst wiederholende Event-Listener-Boilerplate-Code für vorübergehende UI-Elemente schreiben müssten. Wenn der Zustand während des Navigierens erhalten bleiben muss, zwischen Benutzern geteilt werden soll, Berechtigungen durchgesetzt oder an Transaktionen teilgenommen werden muss, gehört er auf den Server.

    Navigieren durch die Historie: Neuer Abruf statt Wiederherstellung von Snapshots

    Htmx 2 speicherte Historiensnapschüsse in localStorage. Die Wiederherstellung eines solchen Snapshots könnte DOM-Änderungen zurückbringen, die von unzusammenhängenden Skripten vorgenommen wurden, ohne den JavaScript-Laufzeitzustand wiederherzustellen, der sie erstellt hat. Die Seite sah interaktiv aus, war aber in Wirklichkeit ein „versteinertes“ DOM: Widgets wurden angezeigt, doch dahinter war nichts verbunden.

    Htmx 4 löscht diesen Standard-Cache. Bei Rück- und Vorwärtsnavigierung lädt es die Seite erneut und ersetzt das Ergebnis durch den Inhalt innerhalb von <body> oder in ein speziell dafür vorgesehenes Historie-Element. Angemessene HTTP-Caching-Header können diese Anfrage nahezu kostenlos gestalten, während den Skripten dennoch ein sauberer Dokumententext zur Initialisierung zur Verfügung steht.

    Anwendungen, die tatsächlich lokale Snapshots benötigen, können die Erweiterung hx-history-cache laden, die sessionStorage verwendet und das Verhalten klar definiert. Dieses Muster gilt in der gesamten Version: Eine frische Darstellung ist Standard, während die lokale Rekonstruktion eine optional verfügbare Funktion mit eigener Bezeichnung ist.

    Betrachten Sie die Migration als Verhaltensprüfung

    Der sicherste Upgrade ist kein blindes Austauschen von Paketen, sondern eine kurze Überprüfung aller Stellen, an denen sich das Verhalten außerhalb der Markup-Grenzen bewegt. Die meisten Seiten behalten ihr Markup unverändert; die Arbeit konzentriert sich auf implizite Vererbung, Event-Listener, Antwortverarbeitung, Historie und Erweiterungen.

    Fixieren Sie zunächst eine genaue htmx 4-Version und führen Sie anschließend den offiziellen Upgrade-Checker aus, der in der Migrationsdokumentation beschrieben ist. Bearbeiten Sie die Ergebnisse in einer Reihenfolge, die Kollisionen zwischen umbenannten Attributen vermeidet:

    1. Umbenennen Sie das alte hx-disable, das „diesen Unterbaum ignorieren“ bedeutete, in hx-ignore.
    2. Nur danach umbenennen Sie hx-disabled-elt in das neue hx-disable. Wenn diese beiden Schritte in umgekehrter Reihenfolge ausgeführt werden, würde versehentlich ein Attribut in das andere umgewandelt.
  • Fügen Sie :inherited dort ein, wo ein Elternelement weiterhin Einfluss auf seine Nachkommen ausüben muss, wobei insbesondere Aufschriften, Bestätigungen, Ziele und Include-Elemente berücksichtigt werden sollten.
  • Erneuern Sie die Namen der Event-Listener und ersetzen Sie entfernte Hilfsfunktionen durch native Browser-APIs.
  • Testen Sie 4xx- und 5xx-Antworten, da diese nun standardmäßig vertauscht werden, und stellen Sie sicher, dass jede von ihnen einen sinnvollen Fragment zurückgibt.
  • Testen Sie jedes hx-delete-Element, da dieses ohne die Verwendung von hx-include keine Daten des umschließenden Formulars mehr sendet.
  • Testen Sie die Navigation vorwärts und rückwärts, die Auflistung außerhalb der normalen Reihenfolge, Zeitlimits, Anfragewarteschlangen sowie alle von Ihnen verwendeten Erweiterungen – denken Sie dabei daran, dass hx-ext nicht mehr vorhanden ist.
  • Wann htmx 4 das richtige Werkzeug ist

    Der Titelwechsel lautet Fetch, doch das durchgängige Thema ist die Explizitheit. Ein Attribut erreicht nur dann seine Nachkommen, wenn dessen Deklaration dies vorsieht. Der HTML-Inhalt einer fehlgeschlagenen Anfrage wird standardmäßig dem Benutzer angezeigt, wobei die Ausnahmen konfiguriert werden können. Bei Antworten, die mehrere Bereiche betreffen, wird genau angegeben, wohin jeder Teil geht und wie er ersetzt wird. Die Navigation vorwärts und rückwärts lädt eine neue Seite, es sei denn, man aktiviert absichtlich einen benannten Snapshot-Cache. Erweiterungen werden über ein einheitliches Lebenszyklusmodell eingebunden, und die Standard-DOM-Methoden übernehmen dort, wo htmx früher seine eigenen Hilfsfunktionen bereitgestellt hat.

    Zusammen führen diese Maßnahmen zu weniger verstecktem Verhalten, ohne den Anwendungsstatus in ein Client-Framework zu übertragen. Das ist das Gleichgewicht, das htmx anstrebt: reichhaltige Interaktionen, Serverautorität sowie HTML, das weiterhin beschreibt, was die Seite leisten kann.

    Es wird nicht jede Schnittstelle einfacher machen. Ein Grafikeditor, ein Offline-first-Arbeitsbereich oder eine Anwendung, die auf einem stark kollaborativen lokalen Modell basiert, kann eine komplexere Client-Architektur rechtfertigen. Viele Unternehmensanwendungen beinhalten jedoch hauptsächlich Navigation, Formulare, Tabellen, Validierungen und Workflows, die der Server bereits bereitstellt. Für solche Fälle ist es oft einfacher, die fertige Darstellung zurückzusenden, anstatt zwei Zustandsmaschinen synchron zu halten.

    Kernpunkte

    • Das htmx-Modell bleibt unverändert: Elemente sind Hypermedia-Kontrollen, die Antworten bestehen aus HTML und der Server verwaltet den Zustand.
    • Implizite Attributvererbung gibt es nicht mehr; fehlende :inherited-Suffixe sind die häufigste Ursache für stillschweigende Funktionsstörungen, insbesondere bei CSRF-Headern.
    • Fehlerantworten werden standardmäßig ausgetauscht, sodass jeder 4xx- und 5xx-Antwortkörper ein gültiger Fragment für sein Ziel sein muss.
  • <hx-partial> sowie morphing Swaps machen mehrregionale Aktualisierungen und state-preserving Swaps explizit und vorhersehbar.
  • Streaming, client-seitige Interaktivität und History-Caching wurden in optional verfügbare Erweiterungen verlagert, um den Kern klein zu halten.
  • Führen Sie den Upgrade-Checker aus und testen Sie anschließend tatsächliche Anfragenpfade; der Checker findet mögliche Kandidaten, doch nur durch Tests lässt sich feststellen, ob die Anwendung weiterhin funktioniert.
  • Zusätzliche Literatur