Diese neue Syntax will JSX ersetzen

BBetter Stack
컴퓨터/소프트웨어AI/미래기술

Transcript

00:00:00Zuerst hatten wir JSX, dann TSX, aber wir hängen nun schon seit Jahren daran fest.
00:00:04Kann man das nicht verbessern? Nun, vielleicht mit TSRX.
00:00:08Es ist irgendwie ähnlich, aber doch anders.
00:00:10Wir haben keine Funktion, sondern eine Komponente, wir haben Strings für unseren Text,
00:00:14es gibt eine ganz normale if-Anweisung und auch kein return-Statement.
00:00:17Was also ist das, warum gibt es das und sollten Sie es nutzen? Finden wir es heraus.
00:00:21[Musik]
00:00:26Einige von Ihnen haben solchen Code vielleicht schon einmal gesehen,
00:00:29und das liegt daran, dass er vom Schöpfer von Ripple stammt.
00:00:31Das ist ein neues Frontend-Framework, das Rich vor sechs Monaten auf diesem Kanal vorgestellt hat,
00:00:35also abonnieren Sie den Kanal, um bei solchen Themen auf dem Laufenden zu bleiben.
00:00:38Sie haben die in Ripple verwendete Syntax extrahiert
00:00:41und dafür gesorgt, dass sie mit React, Preact, Solid, Vue und natürlich Ripple funktioniert,
00:00:45und viele Leute waren ziemlich begeistert davon.
00:00:47TSRX beschreibt sich selbst als eine Möglichkeit, UI-Komponenten gut lesbar und nah beieinander zu schreiben,
00:00:52sodass Struktur, Styling und Kontrollfluss am selben Ort leben,
00:00:55und das Ergebnis bleibt vollständig abwärtskompatibel mit TypeScript.
00:00:58Aber wenn Sie Ripple noch nie benutzt haben, sind Sie wahrscheinlich immer noch etwas verwirrt darüber, was das bedeutet,
00:01:01gehen wir also die Funktionen durch.
00:01:03Zunächst einmal verwendet man dafür .tsrx-Dateien, was bedeutet, dass wir einen Compiler-Schritt benötigen,
00:01:07aber das ist mit einem Vite-Plugin super einfach einzurichten,
00:01:10und es gibt auch andere Optionen für weitere Frameworks und Runtimes.
00:01:13Was die eigentlichen Komponenten betrifft, schreiben wir hier statt "function" einfach "component",
00:01:17und das ist im Grunde nur ein Schlüsselwort für den Compiler selbst,
00:01:20aber es macht auch deutlich, dass hier Rendering-Logik enthalten sein wird.
00:01:24Ich würde es vielleicht als kleine Verbesserung der Lebensqualität betrachten.
00:01:27Eine Sache fällt jedoch auf: Wir haben hier kein return-Statement,
00:01:30und das liegt daran, dass TSRX auf anweisungsbasiertem JSX basiert,
00:01:33Sie müssen also keinen Komponentenbaum zurückgeben,
00:01:35sondern schreiben Ihr Markup einfach dort hin, wo es gerendert werden soll.
00:01:37Das bedeutet, dass wir einfach ein weiteres Paragraph-Tag über dieser Card ganz oben in der Komponente einfügen können,
00:01:42und es wird genau dort gerendert, wo es geschrieben steht.
00:01:44Sie können in einer Komponente immer noch ein "return" verwenden, aber es muss ein leeres sein,
00:01:47und es wird nur für einen vorzeitigen Abbruch genutzt, sodass die UI und Logik danach übersprungen werden.
00:01:51Mir hat es geholfen, mir TSRX-Komponenten als sehr linear vorzustellen,
00:01:54die Reihenfolge, in der wir den Quellcode schreiben, ist also auch die Reihenfolge des Renderings,
00:01:57einfach von oben nach unten gelesen,
00:01:59aber ich kann mir auch vorstellen, dass es dadurch schwieriger sein könnte, schnell zu sehen, was eine Komponente rendert,
00:02:03während wir bei so etwas wie React einfach direkt zum return-Statement springen würden.
00:02:06Ein weiterer Vorteil von anweisungsbasiertem JSX ist, dass wir viel mehr normales JavaScript verwenden können.
00:02:10Bedingtes Rendering ist beispielsweise super einfach.
00:02:13Es ist einfach eine if-Anweisung, bei Bedarf auch mit else-if und else.
00:02:17In den Bedingungen müssen wir unser JSX einfach als Anweisung platzieren.
00:02:20Dieselbe Struktur verwandelt sich in React oft in verschachtelte Ternary-Operatoren,
00:02:23weil in JSX jeder Zweig ein Ausdruck sein muss,
00:02:26daher finde ich, dass die TSRX-Version manchmal einfacher zu lesen ist,
00:02:29besonders wenn wir eine komplexere Anweisung haben,
00:02:31aber gleichermaßen kann ich auch sehen, dass dies zu mehr Weitschweifigkeit führen kann,
00:02:35besonders wenn man nur eine einfache Bedingung braucht.
00:02:37Das Gleiche gilt auch für Switch-Statements.
00:02:39Sie können einfach ein normales JavaScript-Switch mit Ihren Cases verwenden
00:02:41und dem JSX, das Sie für jeden Fall rendern möchten.
00:02:44Das ist etwas einfacher als die Handhabung in React,
00:02:47wo man eine Funktion benötigt, um dasselbe Muster zu verwenden,
00:02:49TSRX ist hier also etwas sauberer,
00:02:51aber ein Bereich, der mir persönlich bei TSRX weniger gefällt, ist das Rendern von Listen.
00:02:55Hier verzichten wir auf .map und verwenden stattdessen eine for-of-Schleife,
00:02:58und TSRX hat diese Schleife tatsächlich erweitert, sodass wir den Index
00:03:01sowie eine stabile Identität mit dem Key herausholen können.
00:03:03Wenn Sie dann ein Element überspringen wollen, können Sie einfach "continue" verwenden,
00:03:06es ist also wieder etwas näher am Vanilla-JavaScript-Ablauf,
00:03:08aber wie gesagt, ich habe mich sehr an .map, .filter und so weiter gewöhnt,
00:03:12sodass ich wahrscheinlich eher dabei bleiben werde,
00:03:14und es ist auch erwähnenswert, dass man keine anderen Schleifentypen verwenden kann
00:03:17wie for, for-in, while und do-while.
00:03:19Das funktioniert ausschließlich mit for-of.
00:03:21Um den Trend der Nutzung von normalem JavaScript fortzusetzen:
00:03:23Error Boundaries setzen wir in TSRX mit einem einfachen try-catch-Block um.
00:03:27Nichts Extravagantes und ziemlich selbsterklärend.
00:03:30Wir können denselben try-catch-Block auch verwenden, wenn wir asynchrone Grenzen benötigen,
00:03:33wir müssen einfach nur einen pending-Block hinzufügen
00:03:35und dann dort Ihre Ladekomponente hineinschreiben.
00:03:38Der Compiler kümmert sich darum, diesen Code zu nehmen
00:03:40und ihn für das jeweils verwendete Framework aufzulösen,
00:03:42unter React, Preact und Solid wird hierfür also "lazy" verwendet,
00:03:45und in Ripple ist es das entsprechende Ripple-Äquivalent.
00:03:47Wenn wir aber speziell über React sprechen,
00:03:48scheinen uns die Funktionen, die wir uns bisher angesehen haben,
00:03:50zu erlauben, eine der wichtigsten Regeln von React zu brechen:
00:03:53die Rules of Hooks.
00:03:54Wir können sie nun hinter Bedingungen, vorzeitigen Returns
00:03:57und sogar innerhalb von Schleifen platzieren.
00:03:58Sie werden alle ganz normal funktionieren.
00:04:00Dadurch können wir unseren Code besser dort platzieren, wo er tatsächlich gebraucht wird,
00:04:03und die endgültige Ausgabe bricht die Regeln nicht einmal.
00:04:06Der Compiler schiebt jeden Hook im Stillen an den Anfang der generierten Funktion,
00:04:09sodass React sie immer noch in einer stabilen Reihenfolge sieht,
00:04:11aber Sie dürfen sie dorthin schreiben, wo sie eigentlich hingehören.
00:04:14Für mich, der ich React seit Jahren benutze,
00:04:16ist das eine der Sachen, an die ich mich nur schwer gewöhnen kann,
00:04:18und es ist auch eine Funktion, bei der wir den Compiler
00:04:20eine Menge Magie hinter den Kulissen machen lassen,
00:04:22speziell im Hinblick auf ein Framework,
00:04:24und ich denke, wenn ich das debuggen müsste,
00:04:26könnte ich mich ein wenig darin verlieren, welcher Code wo gelandet ist.
00:04:28Als Nächstes haben wir jedoch den lexikalischen Scope (lexical scoping),
00:04:30jedes verschachtelte Element erstellt also seinen eigenen Gültigkeitsbereich,
00:04:32sodass wir hier eine "const label" in drei verschiedenen div-Blöcken deklarieren können,
00:04:36ohne dass sie kollidieren.
00:04:37Es gibt sogar eine ganz oben in der Funktion, die von nichts gelesen wird,
00:04:40und auch sie führt zu keinem Konflikt.
00:04:41Das Gleiche gilt für jede if-, for-, switch- oder try-Anweisung.
00:04:44Jede hat ihre eigenen Scopes,
00:04:46sodass die deklarierten Variablen, ausgeführten Funktionen
00:04:48und abgeleiteten Werte nicht in die anderen Gültigkeitsbereiche durchsickern.
00:04:51Dies ist eine weitere Funktion, die darauf abzielt, unseren Code am selben Ort zu bündeln,
00:04:54und wieder sorgt sie dafür, dass sich unsere Komponenten linear von oben nach unten lesen lassen.
00:04:57Lassen Sie uns nun von JavaScript abweichen und über Styling sprechen.
00:05:00In TSRX haben wir tatsächlich scoped Styles,
00:05:02Sie können also einfach einen style-Block in Ihre Komponente einfügen,
00:05:04und das CSS, das wir dort schreiben, ist nur auf diese Komponente beschränkt,
00:05:08da beim Kompilieren ein eindeutiger Hash an den Klassennamen angehängt wird.
00:05:11Diese Card-Komponente hat also eine Card-Klasse,
00:05:13und beachten Sie hier, dass auch sie versucht, diese Card-Klasse zu verwenden,
00:05:16aber sie erhält nichts von dem Card-Styling,
00:05:17weil sie keinen eigenen style-Block hat.
00:05:19Sie übernimmt nicht den Stil des übergeordneten Elements,
00:05:21weil ihr dieser eindeutige Hash fehlt.
00:05:22Wenn Sie jedoch Stile über Komponenten hinweg teilen möchten,
00:05:24bietet TSRX ein "style"-Schlüsselwort,
00:05:26sodass das übergeordnete Element den Stilnamen mit diesem Schlüsselwort
00:05:29an eine Komponente übergibt, die "className" als Prop akzeptiert,
00:05:31und es stellt sicher, dass der generierte eindeutige Hash mitgegeben wird.
00:05:35So hat es nun denselben Stil wie das Elternelement.
00:05:37Sie können technisch gesehen auch einen globalen Selektor um Ihre Stile herum verwenden,
00:05:40um das Scoping zu umgehen und diese Stile global anzuwenden,
00:05:42aber ich denke, das wird etwas unübersichtlich
00:05:44und man verliert den Überblick darüber, woher die Stile kommen.
00:05:46Ich persönlich bin durch und durch ein Tailwind-Typ,
00:05:48daher werde ich diese Funktion wahrscheinlich nicht oft nutzen
00:05:50und bei Tailwind bleiben,
00:05:51aber sie ist trotzdem ziemlich cool.
00:05:53Als Nächstes kommt eine Funktion für diejenigen unter Ihnen, die gut aufgepasst haben.
00:05:56In den gezeigten Codeblöcken
00:05:57gab es einen kleinen Unterschied in der Art und Weise, wie Text in diesen Anweisungen behandelt wird.
00:06:01Reiner Text innerhalb eines Elements muss in doppelten Anführungszeichen stehen.
00:06:04Wir können ihn nicht einfach so hineinschreiben wie in JSX.
00:06:07Sie können aber immer noch dynamische Werte verwenden,
00:06:08und in einer Zeile wie dieser,
00:06:10die sich zwischen zwei in doppelten Anführungszeichen gesetzten Strings befindet,
00:06:12verkettet TSRX dies beim Kompilieren einfach zu einem einzigen String.
00:06:16Eine andere Möglichkeit ist, einfach bei einem Template-Literal zu bleiben.
00:06:19Es führt zum gleichen Ergebnis.
00:06:20Für mich war das eines der kleinen Ärgernisse bei der Nutzung von TSRX,
00:06:23weil ich es einfach so sehr im Muskelgedächtnis habe, keine Anführungszeichen für Text zu verwenden.
00:06:26Eine weitere textbasierte Funktion ist jedoch,
00:06:27dass TSRX tatsächlich Strings verarbeiten kann, die echtes HTML-Markup enthalten,
00:06:31und man hat zwei Möglichkeiten, dies zu rendern.
00:06:33Die erste ist die Verwendung des Schlüsselworts "text",
00:06:35welches den escaped Text rendert,
00:06:38sodass Sie den literalen HTML-String sehen,
00:06:40und es ist zudem sicher vor Cross-Site-Scripting (XSS).
00:06:42Das ist also nützlich, wenn Sie garantieren wollen, dass etwas ein String sein wird,
00:06:45die Quelle dieses Strings aber etwas unklar ist,
00:06:48sodass Sie beim Schreiben des Codes nicht unbedingt dessen Typ kennen.
00:06:51Die zweite Option ist für den Fall, dass Sie den String als HTML rendern möchten,
00:06:54wo wir einfach das Schlüsselwort "html" verwenden können,
00:06:56und das parst es als echtes HTML,
00:06:58aber diese Funktion läuft nur in Ripple, während Vue eine kleinere Untermenge davon unterstützt.
00:07:02Ein weiteres Feature, das nichts mit React zu tun hat,
00:07:03aber für diejenigen interessant sein könnte, die Ripple,
00:07:06Vue oder Solid nutzen, ist "lazy destructuring".
00:07:08Wenn Sie Ihre Props in diesen Frameworks normal destrukturieren,
00:07:10erstellen Sie zum Aufrufzeitpunkt eine Momentaufnahme jedes Wertes,
00:07:12und das bricht die Reaktivität beim jeweiligen Zugriff.
00:07:14In TSRX können Sie also einfach ein Kaufmanns-Und (&) vor die Props setzen,
00:07:18und obwohl es wie Destrukturierung aussieht,
00:07:20wird jede Bindung bei der Verwendung tatsächlich wieder in ein Property-Lookup kompiliert.
00:07:23Die Runtime sieht also jeden Zugriff einzeln,
00:07:25sodass Signal-Updates immer noch Re-Renderings auslösen,
00:07:28was bedeutet, dass Sie die Ergonomie der Destrukturierung beibehalten,
00:07:30während das Framework seine Reaktivität behält.
00:07:32Die letzte Funktion, die ich zeige, ist eine nette und einfache Verbesserung der Lebensqualität.
00:07:35Hatten Sie jemals ein Prop, bei dem der übergebene Wert denselben Namen wie das Prop selbst hatte,
00:07:40am häufigsten bei so etwas wie einer on-change-Funktion?
00:07:42Nun, mit TSRX können Sie das einfach als Shorthand schreiben,
00:07:45ähnlich wie bei JavaScript-Objekten.
00:07:47Es ist sauber und einfach.
00:07:49Insgesamt fühlt es sich so an, als ob TSRX versucht, den normalen JavaScript-Fluss wieder in JSX zu integrieren
00:07:53und zudem ein paar Verbesserungen für den Alltag hinzuzufügen,
00:07:55und mir gefallen viele der Elemente wirklich gut.
00:07:57Ich denke wirklich, das größte Manko ist, dass es zu nischig und zu spät dran ist,
00:08:01jetzt, wo KI den Großteil unseres Codes schreibt,
00:08:03und der Code, den KI am besten schreiben kann, scheint JSX und React zu sein.
00:08:07Abgesehen davon habe ich Claude einige Demos mit TSRX vorgeworfen,
00:08:10und es hat es geschafft, den Code allein basierend auf der llm.txt der Website gut zu schreiben,
00:08:14aber ich denke, ich werde selbst trotzdem bei normalem React bleiben.
00:08:17Der andere Nachteil ist, dass es sich besonders bei React so anfühlt,
00:08:19als würde hier noch mehr Compiler-Magie oben draufgepackt,
00:08:21und es bricht auch mit Abläufen, die ich jahrelang gelernt habe,
00:08:24es ist also persönlich nichts für mich, aber das bedeutet nicht, dass es schlecht ist.
00:08:27Ich denke, Leute, die von Svelte kommen, könnten das hier sehr mögen,
00:08:30und wenn Sie Ripple bereits nutzen, lieben Sie das hier wahrscheinlich schon.
00:08:33Schreiben Sie mir also gerne unten in die Kommentare, falls das so ist,
00:08:35lassen Sie bei der Gelegenheit ein Abo da, und wie immer: Bis zum nächsten Mal.
00:08:40[Musik]

Key Takeaway

TSRX bringt anweisungsbasiertes JSX, scoped CSS und compilergesteuerte Hook-Flexibilität in etablierte Frameworks wie React und Solid, bleibt jedoch aufgrund der starken Abhängigkeit von Compiler-Magie und der Dominanz von Standard-JSX in KI-Generierungstools ein Nischenwerkzeug.

Highlights

  • TSRX ist eine neue Syntax für Benutzeroberflächen, die Struktur, Styling und Kontrollfluss abwärtskompatibel mit TypeScript an einem einzigen Ort vereint.

  • Der TSRX-Compiler schiebt React-Hooks im Hintergrund automatisch an den Anfang der generierten Funktion, wodurch Entwickler Hooks regelkonform innerhalb von Schleifen und Bedingungen schreiben können.

  • Das Framework bietet ein Vite-Plugin für die Integration und unterstützt React, Preact, Solid, Vue sowie das neue Frontend-Framework Ripple.

  • Variablen und Funktionen in TSRX besitzen einen strikten lexikalischen Scope innerhalb von if-, for-, switch- und try-Blöcken, wodurch Konflikte zwischen gleichnamigen Deklarationen verhindert werden.

  • Zur Vermeidung von Reaktivitätsverlusten beim Destrukturieren von Props in Frameworks wie Vue oder Solid maskiert das Kaufmanns-Und (&) die Destrukturierung und kompiliert sie in ein klassisches Property-Lookup.

Timeline

Grundkonzept und anweisungsbasiertes Rendering

  • TSRX ersetzt die klassische Funktion durch das Schlüsselwort "component" als Signal für den Compiler.
  • Komponenten benötigen kein return-Statement, da TSRX auf anweisungsbasiertem JSX aufbaut.
  • Ein leeres return-Statement dient in dieser linearen Struktur ausschließlich dem vorzeitigen Abbruch des Renderings.

Die Syntax stammt aus dem vor sechs Monaten vorgestellten Frontend-Framework Ripple und wurde für die Nutzung in React, Preact, Solid und Vue extrahiert. Der Verzicht auf einen zurückgegebenen Komponentenbaum führt dazu, dass Markup direkt an der Stelle des Quellcodes gerendert wird, an der es geschrieben steht. Dies etabliert einen linearen Rendering-Fluss von oben nach unten, erschwert jedoch im Vergleich zu React das schnelle Erfassen der gesamten Render-Ausgabe einer Komponente.

Kontrollfluss und Listenverarbeitung mit nativem JavaScript

  • Bedingte Abfragen nutzen normale if-else- und switch-Anweisungen anstelle von verschachtelten Ternary-Operatoren.
  • Das Rendern von Listen erfolgt über eine modifizierte for-of-Schleife, die den Index und einen stabilen Key bereitstellt.
  • Andere Schleifentypen wie for, while oder do-while sind in TSRX für das Rendering ausgeschlossen.

Die Integration nativer JavaScript-Strukturen vereinfacht komplexe Bedingungen, die in klassischem JSX oft schwer lesbare Ausdrücke erfordern. In der for-of-Schleife erlaubt das Schlüsselwort "continue" das gezielte Überspringen von Elementen, was den Kontrollfluss näher an Vanilla-JavaScript bringt. Diese Abkehr von etablierten Mustern wie .map und .filter verlangt Entwicklern jedoch eine Umgewöhnung ab.

Fehlerbehandlung, Asynchronität und das Aufheben der Hook-Regeln

  • Fehlergrenzen und asynchrone Ladezustände werden über try-catch-Blöcke mit optionalen pending-Blöcken gelöst.
  • Entwickler können React-Hooks innerhalb von Bedingungen, Schleifen und vorzeitigen Returns platzieren.
  • Der Compiler sortiert Hooks im Hintergrund automatisch in eine stabile Reihenfolge am Anfang der generierten Funktion.

Der Compiler löst try-catch-Blöcke je nach Ziel-Framework auf, beispielsweise unter Nutzung von "lazy" in React, Preact und Solid. Die Möglichkeit, Hooks direkt dort zu platzieren, wo sie benötigt werden, bricht optisch mit den traditionellen Rules of Hooks, ohne die Laufzeitregeln von React zu verletzen. Diese starke Compiler-Magie erleichtert zwar das Schreiben des Codes, erhöht jedoch die Komplexität bei der Fehlersuche und dem Debugging des generierten Codes.

Lexikalischer Scope und komponentenbezogenes CSS-Styling

  • Jeder verschachtelte Block wie if oder for erzeugt einen eigenen lexikalischen Gültigkeitsbereich.
  • Integrierte style-Blöcke begrenzen CSS-Regeln automatisch über einen eindeutigen Hash auf die jeweilige Komponente.
  • Das Schlüsselwort "style" ermöglicht die gezielte Weitergabe von Scoped-Styles an Kindkomponenten.

Gleichnamige Variablen kollidieren dank des strikten Scoping selbst dann nicht, wenn sie in verschiedenen div-Blöcken oder auf oberster Ebene deklariert sind. Das integrierte CSS-Scoping verhindert das ungewollte Vererben von Stilen an Kindelemente, da Klassen ohne passenden Hash ignoriert werden. Für globale Stile existiert ein globaler Selektor, dessen Nutzung jedoch die Nachverfolgbarkeit von CSS-Quellen erschwert.

Textverarbeitung, Reaktivität und vereinfachte Objekt-Shorthands

  • Reiner Text innerhalb von Elementen erfordert im Gegensatz zu JSX zwingend doppelte Anführungszeichen.
  • Das Präfix "&" bei der Props-Destrukturierung bewahrt die Reaktivität von Signal-Updates in Vue und Solid.
  • Gleichnamige Props und Werte lassen sich über eine kompakte Shorthand-Syntax wie bei JavaScript-Objekten schreiben.

TSRX bietet dedizierte Schlüsselwörter wie "text" für sicheren, escaped HTML-Text und "html" für das direkte Parsen von Markup, wobei letzteres primär in Ripple unterstützt wird. Die Syntax korrigiert Alltagsprobleme wie doppelte Deklarationen bei Event-Handlern und Reaktivitätsverluste beim Destrukturieren. Trotz dieser ergonomischen Vorteile bleibt die Syntax eine Nischenlösung, da moderne KI-Modelle wie Claude Code primär auf Basis des weit verbreiteten Standard-React und JSX generieren.

Community Posts

View all posts