Svelte 5 ist nicht JavaScript
(hodlbod.npub.pro)- Zusammenfassung der Probleme, die nach dem Upgrade einer Webanwendung auf die aktuelle Version Svelte 5 aufgetreten sind
- Unerwartetes Verhalten trat durch Deep Reactivity und den geänderten Lifecycle auf
- Obwohl Svelte 3/4 lange sehr geschätzt wurde, wird Svelte künftig wohl nicht mehr für neue Projekte gewählt werden
Die Notwendigkeit von Geschwindigkeit
- Das Svelte-Team versuchte mit Deep Reactivity eine Performance-Optimierung und erreichte dadurch bessere Leistung
- Schon zuvor bot Svelte durch den Compile-Prozess hohe Geschwindigkeit, was eine besondere Stärke gegenüber anderen Frameworks war
- Dadurch wurde das Framework zwar undurchsichtiger und das Debugging schwieriger, aber das erschien als vertretbarer Trade-off zwischen Performance und Produktivität
Die Notwendigkeit von Geschwindigkeit
- Die zentrale Änderung, auf die sich das Svelte-Team in Svelte 5 konzentriert, ist „Deep Reactivity“, also der Versuch, die Performance durch feinere Reaktivität zu steigern
- In früheren Svelte-Versionen wurde dieses Ziel vor allem mit dem Svelte-Compiler erreicht
- Dass Entwickler dafür keine neuen Konzepte lernen mussten und interne Logik leicht umstrukturieren konnten, unterstrich die Eigenständigkeit von Svelte
- Gleichzeitig machte dieser Compile-Prozess das Framework undurchsichtiger, was das Debugging komplexer Probleme erschwerte
- Durch Bugs im Compiler selbst traten Fehler auf, deren Ursache schwer zu finden war, und manchmal ließ sich das Problem nur durch ein vollständiges Refactoring der betroffenen Komponente beheben
- Trotzdem wirkte es weiterhin wie ein vernünftiger Trade-off in Bezug auf Geschwindigkeit und Produktivität, sodass sogar die Unannehmlichkeit in Kauf genommen wurde, Projekte regelmäßig zurückzusetzen
Svelte ist nicht JavaScript
- Svelte 5 verdoppelt diesen Trade-off
- Der entscheidende Unterschied ist, dass der Kompromiss zwischen Abstraktion und Performance nun über die Compile-Phase hinaus bis in den Runtime-Bereich hineinreicht
- Einsatz von Proxys zur Unterstützung von Deep Reactivity
- Impliziter Komponenten-Lifecycle-Status
- Diese beiden Änderungen verbessern die Performance und lassen die Entwickler-API eleganter erscheinen
- Was sollte daran schlecht sein? Leider sind diese beiden Funktionen ein typisches Beispiel für eine leaky abstraction
- Am Ende entsteht für Entwickler eine komplexere Umgebung
Proxys sind keine Objekte
- Durch den Einsatz von Proxys konnte das Svelte-Team die Framework-Performance etwas weiter steigern, ohne zusätzliche Arbeit von Entwicklern zu verlangen
- In Frameworks wie React führen Zustände, die über mehrere Komponenten hinweg weitergereicht werden, leicht zu unnötigen Re-Renderings; Svelte führte Proxys ein, um das zu verringern
- Der Svelte-Compiler vermied bereits zuvor einige Probleme, die beim Vergleich eines Virtual DOM auftreten können, doch offenbar wurde angenommen, dass sich die Performance mit Proxys weiter verbessern lässt
- Das Svelte-Team erklärte außerdem, Proxys würden auch die Developer Experience verbessern, und vertrat die Ansicht, dass sich damit „sowohl Effizienz als auch Benutzerfreundlichkeit maximieren“ ließen
- Das Problem ist, dass Svelte 5 oberflächlich einfacher wirkt, in Wirklichkeit aber mehr Abstraktion hinzufügt
- Wenn zum Beispiel ein Proxy zur Erkennung von Array-Methoden verwendet wird, entfällt der Vorteil, in Svelte 4 Code wie
value = valueschreiben zu müssen - In Svelte 4 mussten Entwickler die Funktionsweise des Compilers in gewissem Maß verstehen, um Reaktivität auszulösen. Svelte 5 vermittelt dagegen den Eindruck, man könne „den Compiler vergessen“, doch in der Praxis stimmt das nicht
- Mit der neuen Abstraktion kommt zwar mehr Bequemlichkeit, zugleich steigen aber auch die Regeln, die Entwickler kennen müssen, damit der Compiler wie gewünscht arbeitet
- Wenn zum Beispiel ein Proxy zur Erkennung von Array-Methoden verwendet wird, entfällt der Vorteil, in Svelte 4 Code wie
- Nach langer Nutzung von Svelte wurden persönlich mit der Zeit häufiger Svelte-Stores und seltener reaktive Deklarationen verwendet
- Svelte-Stores liegen konzeptionell näher an grundlegendem JavaScript, der Aufruf der Methode
updateist einfach, und die$-Syntax war eher ein zusätzlicher Vorteil - Wie reaktive Deklarationen erzeugen Proxys das Problem, dass „etwas wie eins aussieht, sich an den tatsächlichen Grenzen aber anders verhält“
- Svelte-Stores liegen konzeptionell näher an grundlegendem JavaScript, der Aufruf der Methode
- Beim ersten Einsatz von Svelte 5 schien alles gut zu funktionieren, doch beim Versuch, Proxy-Status in IndexedDB zu speichern, trat ein
DataCloneErrorauf- Noch dazu muss man, um sicher festzustellen, welche Werte Proxys sind, strukturierte Klone mit
try/catchausprobieren, was Performance kostet - Letztlich muss man sich also merken, was ein Proxy ist, und in Kontexten, die Proxys von außen nicht erkennen, jedes Mal
$state.snapshotverwenden - Das führt am Ende dazu, dass die ursprüngliche Absicht „Abstraktion erhöht die Entwicklerfreundlichkeit“ ins Gegenteil kippt und Entwicklern mehr komplexe Regeln und Abläufe abverlangt
- Noch dazu muss man, um sicher festzustellen, welche Werte Proxys sind, strukturierte Klone mit
Komponenten sind keine Funktionen
- Der Grund, warum das Virtual DOM um 2013 populär wurde, war, dass sich Anwendungen als Kombinationen von Funktionen modellieren ließen
- Svelte setzte statt auf ein Virtual DOM auf einen Compiler, um Lifecycle-Funktionen zu vereinfachen und die Performance zu steigern
- In Svelte 5 wurde das Lifecycle-Konzept jedoch in einer Form wieder hinzugefügt, die React Hooks ähnelt
- In React sind Hooks ein Abstraktionskonzept, das zustandsbezogenen Code in Lifecycle-Methoden reduziert
- Der Code wird sauberer, aber es gibt viele Punkte, auf die Entwickler achten müssen, etwa wenn in
setTimeoutauf Status zugegriffen wird - Auch in Svelte 4 konnte es Probleme geben, wenn asynchroner Code beim Unmount einer Komponente noch auf DOM-Elemente zugriff
- In Svelte 5 scheint nun impliziter Status zum Komponenten-Lifecycle hinzugekommen zu sein, um Zustandsänderungen und Effekte zu koordinieren
- Der Code wird sauberer, aber es gibt viele Punkte, auf die Entwickler achten müssen, etwa wenn in
- Die offizielle Dokumentation zu $effect beschreibt dies wie folgt:
„$effect kann überall platziert werden, muss aber während der Initialisierung einer Komponente (oder während ein übergeordneter Effekt aktiv ist) aufgerufen werden und verschwindet, wenn die Komponente (oder der übergeordnete Effekt) unmounted wird“
- Das deutet darauf hin, dass es entgegen der Aussage, der Lifecycle bestehe nur aus den zwei Phasen Mount/Unmount, tatsächlich eine komplexe Effektstruktur gibt, in der Zustandsänderungen verfolgt werden müssen
- In der offiziellen Lifecycle-Dokumentation heißt es zwar, es gebe kein „before update/after update“, doch gleichzeitig tauchen neue Konzepte wie
$effect.preundtickauf - Das bedeutet faktisch, dass man neben Mount/Unmount auch den Zeitpunkt von Zustandsänderungen verstehen muss
- Das Problem im praktischen Einsatz war, dass selbst Status, der an eine mit Svelte nicht zusammenhängende Funktion übergeben wird, an den Komponenten-Lifecycle gebunden bleibt
- Zum Beispiel wurde ein Muster verwendet, bei dem ein Modal-Fenster über einen Store verwaltet und ein Callback an eine Kindkomponente weitergegeben wird
const { value } = $props() const callback = () => console.log(value) const openModal = () => pushModal(MyModal, { callback }) - Wenn sich dieser Code innerhalb der Modal-Komponente befindet, wird zuerst die aufrufende Komponente unmounted, und in diesem Moment ändert sich
valuezuundefined - In diesem Repository gibt es ein minimales Reproduktionsbeispiel
- Das heißt: In einem Callback, der nach dem Ende des Komponenten-Lifecycles weiterlebt, werden zuvor referenzierte Props plötzlich zu
undefined - Dieses Verhalten unterscheidet sich von normalem JavaScript und wirkt so, als würde Svelte selbst eine Art Garbage Collection durchführen
- Dafür mag es technische Gründe geben, aber das Verhalten ist unerwartet und überraschend
Fazit
- Einfachheit ist ohne Zweifel attraktiv, aber wie Rich Hickey sagte, easy bedeutet nicht automatisch simple
- Wie Joel Spolsky mag ich unerwartetes Verhalten nicht
- Svelte hat bisher viel „Magie“ gezeigt, aber in dieser Version muss man sich zu viel merken, um diese Magie zu nutzen, sodass die Belastung den Nutzen übersteigt
- Der Punkt dieses Artikels ist nicht, das Svelte-Team anzugreifen; vielmehr ist bewusst, dass viele Menschen Svelte 5 (und React Hooks) bevorzugen
- Entscheidend ist das Gleichgewicht zwischen Komfort für Nutzer und der Möglichkeit für Nutzer, die Kontrolle zu behalten
- Wirklich gute Software basiert nicht auf „Cleverness“, sondern auf „Verständnis“
- Mit dem Fortschritt von AI-Tools wird es wichtiger, Werkzeuge zu wählen, die vorhandene Erfahrung nutzen und tiefes Verständnis fördern, statt Tools, bei denen man nicht mehr weiß, was man eigentlich tut
- Dank an Rich Harris und das Team für die bislang erfreuliche Entwicklererfahrung. Hoffentlich ist dieser Text kein unzutreffendes Feedback
7 Kommentare
Proxys machen es für die Entwickler bequem, aber wer debuggen muss, wird dabei echt wütend, haha.
Das Nebenprojekt hat bei solidjs die beste DX >_< / glücklich
Ich denke, dass auch React/nextjs durch Alternativen wie Svelte stark herausgefordert werden konnte.
Im Kern ist Svelte eine language, daher hoffe ich, dass es auch gut die Richtung aufzeigt, in die sich eine Sprache zur Beschreibung von UI weiterentwickeln sollte.
Ich werde React verwenden.
Zu viel des Guten
Besessenheit
Aufgesetzte Überkonstruktion
Ich denke, dass sich Svelte 5 unter nicht geringem Einfluss von React und insbesondere Next auf seltsame Weise verändert hat.
+pageist schwer zu verstehen, wenn man Svelte nicht kennt, und Runen wie$stateoder$derivedwirken, als würden sie React folgen; da erschien mir die Zeit, als man einfach$:vor Variablen setzte, fast besser. Auch die altmodische Syntax wie{#each a in array} {/each}ist zwar noch erträglich, aber weiterhin umständlich. Wenn es um Leistungsverbesserungen durch optionale Reaktivität geht, halte ich SolidJS für einen deutlich besseren Ansatz. Da es JSX unverändert verwendet, ist der Umstieg von React aus auch vergleichsweise leicht. Es ist fast erstaunlich, dass SolidJS verhältnismäßig so wenig Aufmerksamkeit bekommt.Ich habe den Eindruck, dass Signals sich auf den
Trough of disillusionmentdes Gartner hype cycle zubewegt 🤔 Mit der schrittweisen Etablierung von Use Cases könnte sich die Bewertung nach und nach verbessern.Hacker-News-Kommentare
Anfangs fand ich runes nicht besonders interessant. Meine Meinung änderte sich jedoch, als ich externe reaktive Komponenten in
.svelte-Templates importieren und die Reaktivität intern kapseln konnte. Das bedeutet, dass manvitest-Tests schreiben und dennoch die Vorteile der Reaktivität nutzen kann. Das ist wirklich mächtig und AFAIK einzigartig in der Frontend-WeltIch entwickle aktiv eine kommerziell ausgerollte SvelteKit-Anwendung und möchte ein paar Gedanken zu dieser Erfahrung teilen
+pagebeschäftigen. Man konnte Svelte-Dateien dort ablegen, wo man wollte, und sie wurden nahtlos gerendert, während man weiterhin die Vorteile moderner Frameworks hatteEs ist schade, dass EmberJS verschwunden ist. Die API war in den letzten 10 Jahren ziemlich stabil. Ironischerweise wird jemand, der in den letzten 10 Jahren EmberJS-Apps geschrieben hat, bei Migrationen vermutlich weniger Schwierigkeiten haben als jemand, der in derselben Zeit dasselbe mit React, Svelte, Vue usw. gemacht hat
Die beiden Github-Links, die der Autor oben im Beitrag aufführt, verweisen auf dasselbe Problem, und für dieses Problem gibt es eine Lösung (
use $state.raw)Svelte 5 ist auf die <i>schlechteste</i> Weise kein JavaScript. Es behebt die Probleme von JS nicht, sondern liefert nur eine undichte Abstraktion für einige Frontend-Probleme. Ich denke, Solid geht in eine bessere Richtung als Svelte. Solid hängt nicht von einer neuen Sprache ab. Aber weil JS nicht ideal ist, gibt es den Impuls, etwas zu bauen, das nicht JS ist. Elm ist der Vorläufer von Svelte. Aber ich denke, wir können etwas Besseres machen ...[0]
Ich habe angefangen, Svelte 5 zu verwenden, weil ich Stores in Svelte 4 wirklich gehasst habe. Ich nutze SvelteKit und Svelte 5 für ein neues Projekt, und ich muss sagen ... Reacts Produktivität ist immer noch unschlagbar, obwohl SvelteKit und Svelte technisch besser sind
+page.server.tsoder+page.svelteoder eine Variante davon, was es schwierig macht, Code leicht zu durchsuchen. Sveltes Tooling existiert getrennt vontscund ESLint, wodurch es schwerer ist, es in CI zu integrieren und in der Entwicklung zu nutzenZu sagen, Svelte sei kein JavaScript, nur wegen unerwartetem Verhalten beim Übergeben von Closures in Callbacks, wirkt seltsam. Ein besserer Titel wäre „Ich mag Svelte 5 nicht, weil es mich überrascht“
Wenn ihr eine Bibliothek sucht, mit der man Komponenten und Apps mit reinem JavaScript bauen kann, schaut euch Lit an: Lit
Wollt ihr ein vernünftiges Frontend-Erlebnis? Dann nutzt Vanilla JavaScript, Web Components, htmx und Blazor