Svelte ist ein JavaScript-Framework zum Entwickeln von Webseiten und Web Apps. Version 3 erschien 2019, und seitdem erfreut sich das Framework wachsender Beliebtheit. Die NPM-Downloadzahlen konnten sich jedes Jahr verdoppeln und liegen jetzt bei etwa einer Million pro Woche.

Die Entwicklung wurde professionalisiert und steht auf festen Füßen: Der Frontend-Cloud-Provider Vercel unterstützt sie durch drei Vollzeit-Entwickler, und zahlreiche weitere Maintainer arbeiten nebenher daran mit.

Mit einer solchen stabilen Basis wurde es Zeit, Svelte einer Generalüberholung zu unterziehen: Was funktioniert gut und sollte beibehalten werden, und was sollte angepasst und verbessert werden? Das Ergebnis ist Svelte 5, welches gerade frisch erschienen ist. Höchste Zeit also, einen Blick auf die Änderungen und neuen APIs zu werfen.

Runes – das Herzstück von Svelte 5

Svelte ermöglicht es, mit fast minimalem Code die eigene UI reaktiv werden zu lassen. Das folgende Beispiel ist alles, was man für einen simplen Counter in Svelte 4 benötigt:

Der Code ist reaktiv, da Svelte zentral auf einen Compiler setzt, um den Code aus Svelte-Dateien in performanten JavaScript-Code umzuwandeln. Der Compiler „sieht“, wo count referenziert wird und kann daraus erkennen, dass countein Zustand ist. Für das Erhöhen des Zählers benötigen wir keine spezielle API, wir weisen count einfach eine neue Zahl zu. double ist immer das Zweifache von count, was durch die $:-Syntax (die übrigens valides JavaScript ist) definiert wird.

Leider funktioniert diese schöne deklarative Welt nur auf der obersten Ebene von Komponenten – möchte man eine wiederverwendbare createCounter-Methode erstellen, kann man die implizite „letist Zustand“-Syntax und die $:-Syntax nicht mehr verwenden. Stattdessen müssen in Svelte 4 sogenannte Stores verwendet werden – Objekte, die ein Container für einen Wert sind, der über eine set-Methode aktualisiert wird, die Konsumenten, die sich über eine subscribe-Methode registrieren, diese Änderung dann mitteilt.

Große Auswahl an günstigen Domain-Endungen – schon ab 0,08 € /Monat
Jetzt Domain-Check starten


Die Umstellung auf Stores ist ein nerviger Refactoring-Aufwand, und das Ergebnis liest sich weniger deklarativ als die ursprüngliche Version. Wäre es nicht schöner, ein und dieselbe deklarative Syntax überall verwenden zu können, egal ob man sich in einer Komponente befindet oder nicht?

Das dachte sich auch das Svelte-Maintainer-Team, und führt deshalb in Svelte 5 eine neue API ein: Runes – zu Deutsch: Runen. Runen sind Buchstaben oder Zeichen, die als magische Symbole genutzt werden. Nüchterner formuliert sind sie Compiler-Anweisungen. So sieht das obige Counter-Beispiel mit der neuen Runes-API aus:

$stateund $derivedsind hier keine Funktionen, sondern Anweisung an den Compiler, diese Variablen besonders zu behandeln und nach Änderungen an ihrem Zustand die Anwendung neu zu rendern. Ansonsten ändert sich am Codebeispiel nichts. Das bedeutet insbesondere, dass das Lesen und Schreiben von Zustand nach wie vor eine einfache =-Anweisung ist – keine zusätzlichen APIs nötig. Aus Nutzersicht ist also der Wert, der in $state und $derived hineingeben wird, auch der, der wieder herauskommt.

Für solch einen einfachen Fall mag das für geübte Svelte-Nutzer auf den ersten Blick wie ein Rückschritt wirken, da es etwas mehr Code erfordert. Auf den zweiten Blick bietet es jedoch zahlreiche Vorteile: Der Code ist lesbarer, da sich unmittelbar nachvollziehen lässt, welche Variablen einen Zustand ausdrücken, und welche nicht, und die auf den ersten Blick verwirrende $:-Syntax gehört der Vergangenheit an. $derived ist außerdem konsistenter: Wann immer der Wert ausgelesen wird, ist er aktuell. $: double= count * 2 wurde immer nur direkt vor dem Rendern der UI auf den neuen Wert aktualisiert, was in der Vergangenheit schon oft zu unangenehmen Überraschungen bei Svelte-Nutzern führte.

Der entscheidende Vorteil von Runes ist, den Code viel einfacher extrahieren und refaktorieren zu können, ohne auf Sveltes Stores zurückgreifen zu müssen. Den gegebenen Code in eine Funktion zu extrahieren, sähe so aus:

Die Getter-Methoden sind nötig, damit die Reaktivität voncount und double bewahrt bleibt und über die Funktionsgrenzen hinweg transportiert wird. So bekommt jede Stelle, die count beziehungsweise double ausliest, den aktuellen Wert zugespielt. Allgemein gesprochen ist dies „Just JavaScript“, denn auch ohne Runes müsste man hier Getter benutzen, wollte mancountund doubleüber Funktionsgrenzen hinweg „live“ halten.

Wer lieber Klassen zur Beschreibung solcher Objekte nutzt, kann das ebenfalls tun. Der Code sähe stattdessen so aus:

Die Verwendung sieht dann folgendermaßen aus:

Neben Zustand und abgeleitetem Zustand gibt es als dritte Kategorie sogenannte Seiteneffekte, zum Beispiel Logging oder imperatives Aktualisieren von Zustand außerhalb des reaktiven Systems. In Svelte 4 wurde dafür die $:-Syntax genutzt:

In Svelte 5 wird dies durch die $effect-Rune ersetzt:

Auch hier gilt: Auf den ersten Blick mag das für erfahrene Svelte-Nutzer wie unnötiger Extra-Code wirken, doch ist es auch hier wesentlich leserlicher und bietet darüber hinaus zusätzliche Vorteile. So kann man bei Bedarf eine Funktion von $effect zurückgeben, die aufgerufen wird, bevor $effect erneut ausgeführt wird, oder bevor die Komponente zerstört wird. Der folgende Code wäre in Svelte 4 deutlich aufwendiger zu schreiben:

Zu guter Letzt gibt es noch die $props-Rune. Sie wird zur Definition der Properties einer Komponente benutzt und ersetzt die bisherigen export let-Definitionen.

Insgesamt erfordern Runes vorab ein kleines bisschen mehr Denkarbeit („ist das hier Zustand? Muss ich hier $derived oder $effect nutzen?“) und minimal mehr Schreibarbeit. Dafür ist der Code leserlicher, wartbarer, leichter neu zu organisieren, und kompliziertere Patterns sind durch die universelle Reaktivität einfacher möglich. Svelte wird zudem noch einfacher zu erlernen, da sich alles, was besonders im Script-Teil einer Komponente ist, durch Runen ausdrücken lässt.

Snippets – zwei Fliegen mit einer Klappe

Runes sind sicherlich die größte Änderung, die uns in Svelte 5 erwartet. Daneben gibt es weitere Änderungen, die darauf abzielen, die Anzahl an Konzepten, die es zu lernen gilt, zu reduzieren und gleichzeitig die Flexibilität des JavaScript-Frameworks zu erhöhen.

Die erste davon sind Snippets. Diese sind – wie der Name schon vermuten lässt – UI-„Schnipsel“, die man innerhalb einer Komponente definieren kann. Von der Syntax sehen sie ähnlich wie Funktionsdefinitionen aus, haben also einen Namen und eine Liste von Parametern. Diese Parameter können sie dann in ihrem Template nutzen. Sie können außerdem alle Variablen nutzen, die in ihrem Scope existieren – so wie auch JavaScript-Funktionen das können. Nur eigene Logik in einem Script-Tag können sie nicht enthalten – wer dies braucht, sollte zu einer Komponente greifen. Snippets sind also sozusagen das kleine Geschwisterkind von Komponenten. Gerendert werden sie mit dem @render-Tag, der wie ein Funktionsaufruf aussieht.

Snippets lösen so ein lange bestehendes Problem in Svelte: Wann immer man UI-Elemente in einer Komponente hatte, die sich wiederholten, stand man vor der Frage, ob man dafür schon eine neue Komponente anlegt, oder die Code-Duplikation in Kauf nimmt. In Svelte 5 kann man stattdessen einfach ein Snippet nutzen.

Doch das ist nicht alles. Snippets schlagen gleich zwei Fliegen mit einer Klappe: Da sie sich wie normale Variablen verhalten, kann man sie auch als Properties an eine Komponente übergeben, und diese kann das Snippet dann an einer passenden Stelle rendern oder weiterreichen.

Damit entpuppen sie sich als bessere Version der Slot-API aus Svelte 4: Statt let:x={y}, <slot name="..">, <svelte:fragment>, $$slots und vielen weiteren umständlichen Bestandteilen der Slot-API kommen nun Snippets zum Einsatz, die leichter zu erlernen und zu verstehen sind und zugleich mehr Flexibilität und Möglichkeiten bieten.

Wenn das Snippet nur für diese Komponente gedacht ist, kann als Kurzschreibweise das Snippet innerhalb der Komponente definiert werden. Damit wird das Snippet implizit als Property desselben Namens in die Komponente hineingereicht.

Event Attributes

Die letzte bedeutsame Änderung sind Event Attributes. In Svelte 4 werden Events durch ein on:-Prefix definiert:

Für DOM-Elemente heißt dies, dass man auf das click-Event hört und als Reaktion die angegebene Funktion ausführt. Für Komponenten kann man theoretisch Callback-Props benutzen, also Properties definieren, die eine Funktion entgegennehmen, die aufgerufen wird, wenn das Event feuert. Für die syntaktische Konsistenz empfiehlt es sich jedoch, stattdessen Sveltes Event-Dispatcher-API zu nutzen – und die ist wesentlich aufwendiger zu schreiben: Man muss eine Methode namens createEventDispatcher importieren, diese aufrufen, und das Ergebnis davon wiederum überall dort aufrufen, wo das Event gefeuert werden soll.

Die so erzeugten Events sind vom Typ CustomEvent, daher müssen Verwender event.detail schreiben, nur um an den eigentlichen Payload zu kommen. Das Weiterreichen von Events ist ebenfalls umständlich, denn jedes Event muss mit der on:-Syntax einzeln weitergegeben werden. Das ist besonders für Komponentenbibliotheken ein Ärgernis, müssen sie doch jedes erdenkliche DOM-Event einzeln weiterreichen – es könnte ja sein, dass einer der zahlreichen Verwender eines dieser Events braucht.

Svelte 5 löst all diese Probleme mit Event Attributes. Statt on:click schreibt man onclick. Alle DOM-Attribute, die mit on beginnen, sind also Events. Dadurch lassen sie sich auf Komponentenebene wie Properties behandeln und entsprechend einfach durchreichen. Das gilt ebenfalls für das Spreaden von Attributen – die darin enthaltenen Elemente, die mit on beginnen, gelten als Events, auf die dann gehört wird. Da Events nun Attribute sind, entfällt der Drang, createEventDispatcher statt Callback-Properties zu nutzen. Im Ergebnis sieht die Nutzung von Events etwa so aus:

Rückwärtskompatibilität ist gesichert

Runes, Event Attributes und Snippets – das sind alles bedeutende Änderungen an der Svelte-API. Wer jetzt denkt „Wie soll ich meinen ganzen Code in einem Rutsch updaten?“ – keine Sorge: Das Svelte-Team ist sehr darauf bedacht, das Upgrade auf Svelte 5 so reibungslos wie möglich zu gestalten. Daher funktioniert die komplette API, die aus Svelte 4 bekannt ist, auch in Svelte 5. Die bisherige Event-Syntax, Slots, auch die alte Syntax rund um $: wird weiter unterstützt. Dies ermöglicht es den meisten Anwendungen, auf Svelte 5 zu upgraden, ohne auch nur eine Zeile Komponentencode anfassen zu müssen, oder darauf zu warten, dass alle Dependencies Svelte 5 unterstützen.

Wer geupgradet hat, kann danach Komponente für Komponente im eigenen Tempo auf die neue Syntax umstellen: Komponenten, die Runes nutzen, können ohne Problem Komponenten verwenden, die noch keine Runes nutzen, und umgekehrt. Und beim Upgrade der Komponenten selbst stellt das Team ein Migrationsskript bereit, welches den Hauptteil der Arbeit übernimmt.

Svelte erfindet sich neu

Mit der Version 5 erfindet sich Svelte ein Stück weit neu. Das Maintainer-Team hat wertvolle Lektionen aus vergangenen Erfahrungen und Rückmeldungen gezogen und beschreitet mit der Runes-API neue Pfade. Snippets und Event Attributes stellen weitere vielversprechende Neuerungen dar, die Entwicklern mehr Flexibilität zum Schreiben ihrer Apps und Libraries eröffnen.

Trotz der zahlreichen Änderungen bleibt die neue Version des UI-Frameworks seinem ursprünglichen Prinzip treu: Es ist weiterhin schlank, leicht erlernbar (sogar mehr denn je) und legt den Fokus auf die Entwicklerzufriedenheit.

Neugierige können den Online-Playground nutzen, um Svelte 5 im Browser auszuprobieren, lokal ist es über den Installationswizard mit npm create svelte@latest installierbar.

Simon Holthausen

Große Auswahl an günstigen Domain-Endungen – schon ab 0,08 € /Monat
Jetzt Domain-Check starten