- Mux hat mux.com und docs.mux.com auf React Server Components umgestellt und dabei festgestellt, dass die Trennung der Ausführungsgrenzen zwischen Server und Client direkte Auswirkungen auf Bundle-Größe und Hydration-Kosten hat
- RSC ermöglicht es Komponenten, Daten direkt auf dem Server abzurufen und das Ergebnis zu streamen, sodass Teile der Oberfläche schon angezeigt werden können, selbst wenn langsame Datenaufrufe noch laufen
- Die größten Hürden der tatsächlichen Migration waren fehlende CSS-in-JS-Unterstützung, Einschränkungen von React Context in Server Components und die Komplexität, die Server/Client-Grenzen laufend nachverfolgen zu müssen
- Im app directory von Next.js 13 sind Komponenten standardmäßig Server Components; indem man
use clientan der Wurzel schrittweise nach unten verschiebt, ist eine schrittweise Einführung möglich - Patterns wie Suspense,
loading.js, das Beibehalten serverseitiger Bibliotheken undserver-onlysollten gezielt nur dort eingesetzt werden, wo Performance-Gewinne nötig sind; auch die kognitive Last fürs Team muss mit einkalkuliert werden
Umfang der RSC-Umstellung bei Mux
- Mux hat im Zuge einer Neustrukturierung der Dokumentationssite und eines Rebrandings mux.com und docs.mux.com auf Server Components umgestellt
- React Server Components sind auch in realen Codebasen einsetzbar und können sich lohnen, bringen aber zugleich Einschränkungen und Komplexität mit sich
- Diese Erfahrung wird entlang der Fragen zusammengefasst, warum RSC nötig sind, wo sie passen, in welchen Situationen sie schwierig werden und wie man sie schrittweise in eine echte Codebasis einführen kann
Das Problem, auf das RSC nach CSR, SSR/SSG abzielt
- Beim frühen Server-Rendering wurden mit Technologien wie PHP Daten auf dem Server abgerufen und rechenintensive CPU-Arbeit erledigt; an den Client wurde nur leichtgewichtiges HTML ausgeliefert
- CSR/SPA schickte den Rendering-Code als JavaScript an den Client und ermöglichte so schnelle Interaktionen, zeigte aber Schwächen, wenn Suchmaschinen JavaScript nicht ausführten, Geheimwerte auf dem Server bleiben mussten oder Nutzer leistungsschwache Geräte bzw. langsame Verbindungen hatten
- SSR/SSG erzeugt mit Tools wie Next.js und Gatsby HTML und JavaScript gemeinsam auf dem Server und sendet beides an den Client
- Nutzer sehen das HTML sofort
- Sobald JavaScript geladen ist, wird die Site interaktiv
- Suchmaschinen können ebenfalls das HTML lesen
- Auch bei bisherigem SSR/SSG bleiben Kosten bestehen
- Ein Großteil des JavaScript, das zur Seitenerzeugung verwendet wurde, wird an den Client gesendet; der Client muss es erneut ausführen und per Hydration mit dem HTML verbinden
- Dauert das Server-Rendering wegen langsamer Datenbankaufrufe oder viel auszuführendem Code lange, müssen Nutzer warten
Was React Server Components verändern
- React Server Components sind React-Komponenten, die nicht auf dem Client, sondern auf dem Server ausgeführt werden
- Frameworks mit RSC-Unterstützung ermöglichen es, explizit zu trennen, wo Code ausgeführt wird
- Server Components: Code, der nur auf dem Server laufen soll
- Client Components: Code, der auf dem Client laufen soll
- Wenn der Ausführungsort getrennt ist, wird weniger JavaScript an den Client gesendet und auch während der Hydration ist weniger Arbeit nötig
- Eine Server Component kann Daten direkt innerhalb der Komponente abrufen
- Sie kann Node-Bibliotheken oder
fetchverwenden - Dadurch lässt sich reduzieren, dass Daten auf Seitenebene gebündelt mit
getServerSidePropsgeholt und dann fortlaufend als props nach unten gereicht werden - Auch Fälle, in denen komplexe Ladezustände mit
useEffectverwaltet werden, nehmen ab
- Sie kann Node-Bibliotheken oder
- Eine Server Component, deren Datenabruf abgeschlossen ist, kann das Ergebnis zum Client streamen
- Der Rest der Site kann zuerst angezeigt werden, während auf eine langsame Komponente gewartet wird
- Es ist auch möglich, als Reaktion auf Nutzeraktionen im Client Daten auf dem Server abzurufen und die Antwort zu streamen; streng genommen gehört das jedoch nicht zu RSC, sondern zu React Actions
Was an RSC schwierig ist
- CSS-in-JS funktioniert derzeit nicht in Server Components
- Bei der RSC-Umstellung von Mux nahm der Wechsel von styled-components zu Tailwind CSS den größten Anteil ein
- Codebasen, die stark von CSS-in-JS abhängen, benötigen zusätzliche Migrationsarbeit
- React Context ist nur in Client Components zugänglich
- Um Daten zwischen Server Components ohne props zu teilen, muss man wahrscheinlich normale Module verwenden
- Einen guten Mechanismus, um Daten auf einen bestimmten Teilbaum einer React-Anwendung zu beschränken, gibt es in Server Components nicht
- Auf der Dokumentationssite von Mux war das kein großes Problem, weil die Bereiche mit Context-Nutzung sehr interaktiv waren und ohnehin an den Client gesendet werden mussten
- Auf der Marketing-Site wurde das Teilen von Theme-Informationen zum Problem
- Jede Komponente im Pre-Footer musste wissen, dass sie auf einem grünen Hintergrund liegt, um einen dunkelgrünen Rahmen verwenden zu können
- Als Umgehung wurden statt Context intensiv CSS custom properties genutzt
- RSC geben Flexibilität beim Ausführungsort und beim Datenabruf, erhöhen aber ebenso die Komplexität
- Neue Entwickler müssen ständig prüfen, „was auf dem Server läuft und was auf dem Client läuft“
- In PRs entsteht immer wieder Feedback zu Code, der unnötig an den Client geschickt wurde
- Während der Entwicklung wurde häufig
console.logeingefügt, um zu prüfen, ob es sich um Server-Logs oder Browser-Logs handelt - Auch Caching bringt zusätzliche Komplexität mit sich
Die grundlegende Nutzung von RSC in Next.js 13
- Zum Zeitpunkt des Schreibens ist die produktionsreife RSC-Implementierung das app directory von Next.js 13
- Im app directory von Next.js 13 sind die Komponenten, die man schreibt, standardmäßig Server Components
- Im Standardzustand wird der Seitencode nicht an den Client gesendet
- An den Client wird nur HTML ausgeliefert
- Wenn man einer Server Component
asynchinzufügt, kann sie innerhalb der Komponente Daten abrufen - Eine Server Component mit langsamem Datenabruf kann mit
React.Suspenseumschlossen werden- Auf dem Client wird zuerst eine Fallback-UI angezeigt
- Sobald der Server die Daten abgerufen und das Rendering abgeschlossen hat, wird die Ergebnis-Komponente gestreamt
- Eine Suspense Boundary kann nicht nur fürs Daten-Streaming verwendet werden, sondern auch für selective hydration, bei der die Hydration-Priorität bestimmter Bereiche je nach Nutzerinteraktion angepasst wird
- Code, der auf dem Client ausgeführt werden muss, erhält am Dateianfang
"use client"- Das nutzt man für Komponenten, die Client-State und Interaktion benötigen, etwa
onClick-Listener oderuseState - Alle Komponenten, die von einer Komponente mit
"use client"importiert werden, werden ebenfalls an den Client gesendet
- Das nutzt man für Komponenten, die Client-State und Interaktion benötigen, etwa
- Bibliotheken, die RSC nicht unterstützen, können in einer Client Component importiert und in das Client-Bundle aufgenommen werden
- Das Beispiel ist eine
ClientMuxPlayer-Komponente, die@mux/mux-player-reactumschließt
- Das Beispiel ist eine
Entscheidungskriterien für Server Component oder Client Component
- Server Components eignen sich für Code, der nicht an den Client gesendet werden muss
- Rendering von Blogartikel-Inhalten
- Aufwendige Arbeiten wie Syntax-Highlighting von Codeblöcken
- Datenabruf
- Client Components eignen sich für UIs, die auf Nutzereingaben reagieren oder deren Zustand sich im Zeitverlauf ändert
useState- Event-Listener
- Client-seitige Interaktion
- Wenn man die gesamte App als Client Components baut, verhält sie sich ähnlich wie ein bisheriges SSR-Framework
- Man muss nicht die gesamte App auf einmal in Server Components umwandeln, sondern kann sie schrittweise dort einführen, wo der Nutzen am größten ist
Drei Schritte zur schrittweisen Einführung in einer echten Codebasis
- Das von Mux verwendete Playbook besteht aus drei Schritten
- Die Direktive
"use client"an der App-Wurzel hinzufügen - Die Direktive im Render-Tree so weit wie möglich nach unten verschieben
- Fortgeschrittene Patterns anwenden, wenn Performance-Probleme sichtbar werden
- Die Direktive
- In Schritt 1 wird
"use client"in der oberstenpage.tsxvon Next.js 13 hinzugefügt, damit sich die App wie bisher verhält - Wenn serverseitiger Datenabruf nötig ist, fügt man eine Server Component als Parent einer Client Component hinzu
- Die Server Component ruft die Daten ab
- Die abgerufenen Daten werden als props an die Client Component übergeben
- Das kann die bisherige Rolle von
getServerSidePropsersetzen
- In Schritt 2 wird
"use client"von der obersten Komponente in Kindkomponenten verschoben- Bei
<Title />, das keinen Client-Code benötigt, kann die Direktive entfernt und reines HTML ausgeliefert werden - Bei
<Player />, das Client-Code benötigt, entstehen Fehler, daher bleibt"use client"erhalten
- Bei
- Dieser Ansatz sorgt dafür, dass bei neuen Komponenten und bestehenden Refactoring-Kandidaten Server Components berücksichtigt werden, und hilft dabei, die Bundle-Größe teilweise zu reduzieren
Patterns, die bei Performance-Problemen angewendet wurden
- Die Mux-Dokumentationssite wird größtenteils statisch generiert, die Changelog-Sidebar stammt jedoch aus einem CMS
- Wenn die Sidebar mit Suspense umschlossen wird, muss der Rest der App nicht warten, bis der CMS-Fetch abgeschlossen ist
- Auch die loading.js-Konvention von Next.js 13 nutzt intern Suspense und Streaming
- Um große Bibliotheken auf dem Server zu halten, müssen Client Components und Server Components passend platziert werden
- Als Beispiel wurde die Syntax-Highlighting-Bibliothek Prism auf dem Server gehalten
Server Components in Client Components mischen
- Komponenten, die eine Client Component importiert, werden zusammen mit ihr zu Client Components
- Wenn man eine Server Component als Kind einer Client Component verwenden möchte, darf man sie nicht importieren, sondern muss sie über
childrenoder props übergeben- Die Server Component wird auf dem Server gerendert
- Das serialisierte Ergebnis wird an die Client Component übergeben
- Der falsche Weg ist, eine Server Component direkt in einer Client-Component-Datei zu importieren
- Der richtige Weg ist, zur nächstgelegenen übergeordneten Server Component hochzugehen und der Client Component die Server Component als Kind oder prop zu übergeben
Eine Datei lässt sich nicht halb Server, halb Client aufteilen
- Es ist nicht möglich, die eine Hälfte einer Datei zur Server Component und die andere Hälfte zur Client Component zu machen
- Mux verwendete häufig ein Pattern, bei dem die Funktionalität auf zwei Dateien aufgeteilt wurde
CodeBlock.server.js: importiert die große Syntax-Highlighting-Bibliothek und rendert auf dem ServerCodeBlock.client.js: verwendetuseStateundonClick, damit Nutzer zwischen Codebeispielen wechseln können
- Die auf dem Server gerenderten Beispiele werden als props an die Client Component übergeben, sodass serverseitige Arbeit nicht ins Client-Bundle gelangt
- Wenn
CodeBlock.server.jsinindex.jserneut exportiert wird, müssen Nutzer nurCodeBlockimportieren und sich nicht um die interne Server/Client-Trennung kümmern
Sicherstellen, dass Code nur auf dem Server ausgeführt wird
- Anfangs wurde während der Entwicklung
console.loghinzugefügt, um zu prüfen, ob die Logs vom Server oder aus dem Browser kamen - Um sicherzustellen, dass serverseitiger Code nicht ins Bundle aufgenommen wird, kann das server-only package importiert werden
server-onlyist nützlich, um zu verhindern, dass große Bibliotheken oder geheime Schlüssel an die falsche Stelle verschoben werden- Next.js stellt Schutzmechanismen bereit, die verhindern, dass Umgebungsvariablen versehentlich im Browser-Bundle landen
server-onlyam Dateianfang hilft auch bei der Wartung- Zuständige sehen sofort, dass diese Datei auf dem Server ausgeführt wird
Kosten und Nutzen bei der Entscheidung für die Einführung
- React Server Components sind keine Funktion, die man kostenlos bekommt
- Zu den Kosten gehören neben Einschränkungen bei CSS-in-JS und React Context auch folgende Punkte
- Verständnis der Ausführungsorte Server und Client
- Verständnis von Hydration
- Infrastrukturkosten
- Code-Komplexität durch das Mischen von Client Components und Server Components
- Komplexität vergrößert die Angriffsfläche für Bugs und kann die Wartbarkeit des Codes senken
- Frameworks reduzieren Komplexität, beseitigen sie aber nicht
- Zu den erwartbaren Vorteilen gehören
- kleinere Bundle-Größen
- schnellere Ausführung
- Performance-Verbesserungen, die für SEO wichtig sind
- fortgeschrittene Datenlade-Patterns für komplexe, datenreiche Sites
- Wenn ein Team bereit ist, die zusätzliche kognitive Last zu tragen, und die Performance-Gewinne groß genug sind, kann RSC gut passen
1 Kommentare
Meinungen auf Hacker News
Bei serverseitigem Rendering bekommt der Client HTML, das sofort sichtbar ist.
Das ist mir auch aufgefallen: Wenn man eine Plaintext-Datei auf den Server legt, wird sie ziemlich schnell an den Browser ausgeliefert.
Legt man eine weitere Plaintext-Datei mit der Endung
.cssdazu, weiß der Browser, wie er sie verarbeiten muss, sodass sich die Elemente auf dem ersten Bildschirm bewegen und vielleicht sogar ziemlich gut aussehen.Ein netter Trick, aber immer noch zweitrangig gegenüber nützlichen Inhalten, die man auf dem ersten Bildschirm lesen kann.
Ich weiß nicht, wie aus „Lasst uns Funktionen hinzufügen, die Hypertext mächtiger machen“ irgendwann „Implementiert euch jetzt selbst brauchbare Anwendungen auf diesem großen, inkonsistenten Haufen von Features“ wurde.
Bevor man sich auf RSC einlässt, sollte man kurz innehalten.
Was auch immer man bauen will, lässt sich mit einem echten Full-Stack-Framework oder einem klassischen Web-Framework viel einfacher, schneller und skalierbarer umsetzen.
Rails/Django/Laravel/… mit Turbolinks/Htmx/… kombinieren oder einfach ein wenig clientseitiges JavaScript einstreuen, reicht oft schon.
Wenn man Elixir/Phoenix kennt, kann man sogar mehrere Vorteile zugleich mitnehmen.
Egal wie viele Leute darüber twittern: Man sollte nicht weiter in Richtung RSC gehen.
Leute mit weniger als 10 Jahren Branchenerfahrung werden wieder über die grundlegenden Probleme stolpern, die man früher bei Vanilla-PHP-Sites hatte; ich habe sogar schon Inline-SQL-Hooks in React-Komponenten gesehen.
Diesmal kommt noch viel mehr zufällige Komplexität obendrauf.
Bleibt bei Verstand, bringt echte Produkte schnell heraus und verdient euch das Geld für den Lamborghini.
CORBA mischt lokale und entfernte Komponenten, ist ausgereift und funktioniert in mehreren Sprachen.
Warum nutzt es dann nicht jeder? Die meisten Entwickler von heute haben wahrscheinlich noch nie davon gehört.
Wer eine weitere Architektur für verteilte Komponenten bauen will, sollte untersuchen, warum CORBA und seine Nachfolger sich nie breit durchgesetzt haben.
Der Hinweis lautet: Versteckte Komponentengrenzen erzeugen versteckte Komplexität.
Gleichzeitig funktionieren die Lager „servergerendertes HTML“ und „clientgerendertes HTML“ beide gut.
Ich finde, wir können uns glücklich schätzen, dass man in jedem Webprojekt beide Optionen nutzen kann.
Ich hoffe, die Arbeit an RSC verwässert nicht Reacts Unterstützung für rein clientgerenderte Apps.
Wenn man nicht zwingend eine vollständige progressive Rich-Frontend-App braucht, erledigt LiveView das meiste über serverseitige Komponenten mit minimalem JavaScript.
Darüber hinaus bekommt jeder Nutzer einen serverseitigen Thread, sodass Änderungen aktiv an das Frontend des Nutzers gepusht werden können, ohne explizite JavaScript-Handler zu schreiben.
Die Branche scheint unter Gedächtnisverlust im 10-Jahres-Zyklus zu leiden.
Es gab sehr gute Gründe, warum man sich von servergerenderten UIs entfernt hat.
Natürlich gibt es immer das Argument der Suchmaschinenoptimierung, aber wenn das eure Sorge ist, baut einfach eine traditionelle Server-Template-Site.
Die überwiegende Mehrheit der Single-Page-Apps braucht SSR und dessen Komplexität überhaupt nicht.
Die ersten Dashboard-Oberflächen wurden komplett mit Phoenix gerendert, und nur auf Seiten, die wirklich anspruchsvolle clientseitige Interaktionen brauchten, wurde React gezielt eingebunden.
Weil unser erstes Produkt ein Analytics-Dashboard war, wurde daraus schnell fast das gesamte Dashboard, und es war naheliegend, auf Basis der API, die wir unseren Kunden bereits bereitstellten, zu einer vollständigen Single-Page-App zu wechseln.
Das war 2016, LiveView gab es also noch nicht, aber ich bin mir nicht sicher, ob wir heute eine andere Entscheidung treffen würden, wenn wir dieses Produkt neu bauen würden.
Der Blogbeitrag handelt von der Anwendung, die unsere öffentliche Marketing-Site betreibt, und deren Anforderungen sind ziemlich anders; ich wollte aber erwähnen, dass auch wir Elixir/Phoenix verwenden und mögen.
Ich habe das Gefühl, alt zu werden
Heutige Frameworks sind viel zu groß und komplex
Selbst ein simples Web-„Hello world“ braucht eine riesige Build- und Compile-Pipeline, und jetzt kommen sogar noch serverseitige Komponenten dazu
Ich frage mich wirklich, wie groß der Overhead ist
Ich weiß nicht, durch wie viele Schichten Frontend- und Backend-Framework-Code ein Hello-World-Beispiel läuft
Ich gehe zurück zu einem einfachen 10-KB-Komponenten-Framework, das neu baut, wenn ich nur F5 drücke
Man optimiert viel zu früh für schicke Features, die vielleicht irgendwann einmal kommen
Das ist so, als würde man sagen, man müsse Ingenieure einstellen, um Kernproben zu nehmen und seismische Modellierung zu betreiben, bevor man einen Hühnerstall baut
Junge Entwickler beginnen das jetzt zu erkennen
So wie wir schreckliche Dinge wie SOAP und XML hinter uns gelassen haben und zu einfacheren, angenehmer nutzbaren Technologien gewechselt sind, lernt auch diese Generation wieder, dass Komplexität schädlich ist
Vielleicht macht Softwareentwicklung für ein paar Jahre wieder Spaß, bevor die nächste Generation wieder alles vermasselt
Eine Pipeline kann je nach Anwendungsfall so komplex oder so einfach sein wie nötig
Man kann nur statische Dateien verwenden, ein kleines Makefile mit einem einzigen
esbuild-Befehl nutzen oder eine riesige Webpack-Konfiguration mit 30 Plugins habenMan kann völlig frei nach den Anforderungen und der Komplexität dessen wählen, was man bauen will
Außerdem ist es nur dann sinnvoll, Tools danach zu bewerten, wie leicht sich damit ein einfaches Hello world bauen lässt, wenn die Arbeit tatsächlich darin besteht, solche Apps zu bauen
Wenn SSR oder Ableger davon ins Gespräch kommen, frage ich mich immer, ob das nicht unnötig alles komplexer macht
React Server Rendering Components klingen, als seien sie zu weit gegangen, und sie widersprechen dem natürlichen Fluss der Developer Experience
Wenn sich die Anwendungskomplexität verdoppelt, es mehr Coding-Fallen gibt und Entwickler langsamer und verwirrter werden, während man nur einen kleinen Performance-Gewinn erhält, frage ich mich, ob es das wert ist
Frühe PHP-Sites und Rails-Apps ohne Single-Page-App haben auch lange gut funktioniert
Ich habe beim Erstellen einer neuen Anwendung mit Next.js und der neuen
app-Verzeichnisstruktur einiges erlebtErstens ist es schwer nachzuvollziehen, was auf dem Server passiert und was auf dem Client
Um das zu wissen, muss man nachforschen, aber wenn man schnell Code schreibt, achtet man meistens nicht besonders darauf
Eine kleine Änderung kann leicht dazu führen, dass große Teile einer Seite plötzlich vom Server auf den Client wandern wollen
Ich weiß, dass ich vor dem finalen Release pro Seite eine vorsichtige und zeitaufwendige Prüfung machen muss, und das gefällt mir nicht
Zweitens gehen viele bestehende React-Libraries davon aus, dass sie im Client ausgeführt werden, weil sie Hooks verwenden
Dadurch kann Code auf den Client gezogen werden
Ziel des Kampfes mit dem neuen Paradigma ist serverseitiges Rendering für schnelles Laden und Suchmaschinenoptimierung, aber wenn importierte Libraries nicht gut mitspielen, ist das komplette Verschwendung
Drittens hat das neue Next.js-
app-Verzeichnisparadigma BugsEs ist noch neu und sehr komplex, sodass dynamische Routes, parallele Routes und deren Zusammenspiel vollständig kaputtgehen können
Ich habe selbst ein Issue auf GitHub von Next.js eröffnet, und es gab viele Kommentare mit „bei mir auch“
Einen der Ansätze, die ich verwendet hatte, hat ein Vercel-Entwickler kürzlich behoben, aber da hatte ich bereits einen anderen Ansatz gewählt, um das Problem zu umgehen
Am nervigsten ist, dass die Entwicklungsumgebung Lazy Loading und Caching-Magie verwendet
Sie scheint Seitenunterschiede zu berechnen und Teil-Updates über etwas wie WebSockets senden zu wollen, aber das kann komplett kaputtgehen und in einen nicht wiederherstellbaren Zustand geraten
Manchmal löst ein Recompile irgendeine Kommunikation vom Server zum Client aus, und wenn ich zum Chrome-Tab zurückkehre, friert der Tab komplett ein, sodass ich den Prozess über den Chrome-Task-Manager beenden muss
Insgesamt ist das alles noch sehr neu und hat viele raue Kanten
Viele Hooks funktionieren auch serverseitig und tun tatsächlich nichts weiter, als Werte zu initialisieren
Interessant ist, dass PHP und JavaScript syntaktisch im Grunde ziemlich nah beieinander lagen.
Der Unterschied beschränkte sich etwa auf das
$-Zeichen oder das Keywordvar, aber NodeJS sagte: „Wir wollen JS auf dem Server ausführen.“Und 15 Jahre später hat JavaScript schließlich aufgeholt und ist praktisch PHP ähnlich geworden – nur mit mehr Abkürzungen und einer steileren Lernkurve.
Natürlich ist es cool, mit Suspense Daten vom Server zu Client-Komponenten zu streamen.
Ich nutze NextJS 13, und mir gefällt, dass es SSR so einfach macht, wie es in PHP schon immer möglich war; ich kann es sehr empfehlen.
Wenn Leute es als „Fraktal schlechten Designs“ bezeichneten, war das zu 100 % nachvollziehbar, und es war berechtigt, sich anderswo nach Lösungen umzusehen.
Heute ist PHP eine deutlich bessere Sprache und einen erneuten Blick wert, aber man sollte nicht so tun, als sei es früher schon so gut gewesen wie heute.
Und man sollte NodeJS nicht am React-Ökosystem messen.
Die enorme Menge an APIs und Wrappern, die nötig ist, um React-basierte Systeme zu betreiben, geht auf das Konto der React-Community.
Klassisches Stockholm-Syndrom.
Viele moderne Fortschritte wurden erst möglich, weil die Browser zuvor besser geworden sind.
Es ist weniger ein vollständiger Kreis als vielmehr ein Gebilde, das aus sehr großer Entfernung wie ein Kreis aussieht.
Einerseits war es innovativ, weil man dank des Nebenläufigkeitsmodells schnellere Backends bauen konnte; andererseits fehlten viele Funktionen etablierter Backend-Sprachen wie Java oder PHP, sodass viele Patterns neu erfunden wurden.
Auch die Sprache selbst brauchte Jahre, um das Niveau an „Sicherheit“ zu erreichen, das Java bereits hatte und auf das PHP zusteuerte.
Bewährte und standardisierte Technologien wie XML und die vertraglichen Garantien, die es bieten konnte, wurden ebenfalls verworfen – mit Begründungen wie, es sei zu schwergewichtig, und JSON sei für Menschen leichter zu lesen und zu schreiben.
Ich habe das Gefühl, dass mit dem Verzicht auf XML viel Zeit und Aufwand verloren ging.
Die Dokumentation von REST/JSON-APIs ist immer noch schmerzhaft.
Schon vor 20 bis 25 Jahren konnte man aus XML-Payloads Datenmodelle und Parser generieren.
Ich weiß bis heute nicht, was an XML so problematisch gewesen sein soll.
Auf der Leitung war es etwas schwerer als JSON, aber das ließ sich mit Kompression oder mit EXI (https://www.w3.org/TR/exi/) lösen, indem man daraus ein binäres Protokoll machte.
Ich weiß nicht, ob sich EXI tatsächlich durchgesetzt hat, aber weil ich damals wusste, wie viel XML unterwegs war, hatte ich recht hohe Erwartungen daran.
Damals sorgte nicht blockierende Ein-/Ausgabe für einen großen Performance-Schub.
In den Köpfen moderner Entwickler scheint es jedoch zu einem dummen Tool degradiert worden zu sein, das JSON ausspuckt oder Toolchains hostet.
Man nutzt wohl, womit man vertraut ist, aber für eine Dokumentationsseite React statt eines fertigen statischen Site-Generators oder CMS mit Caching zu verwenden, wirkt wie Verschwendung.
Aus Entwicklersicht kann React natürlich mehr Spaß machen.
Stripe hat den Trend angestoßen, Code-Snippets mit dem API-Schlüssel des eigenen Kontos anzuzeigen, damit man sie direkt testen kann.
Frontend-Dokumentationsseiten enthalten fast immer ausführbare Beispiele, die man direkt in der Dokumentation ausprobieren kann.
Ein neues Projekt zu bootstrappen ist extrem einfach und schnell – im Grunde einfacher, als ein reines HTML-Projekt zu starten.
Was übersehe ich?
Außerdem interessiert mich die Sichtweise der Leute, die Downvotes geben, wirklich.
Es ist statischer Inhalt; ich verstehe nicht, warum man ihn nicht als HTML generiert und nur ein wenig JavaScript für die Suche hinzufügt.
Der Grund für React ist, im gesamten Frontend eine Sprache zu verwenden.
So vermeidet man, dass die einen auf einer Site React verwenden und andere Gatsby/Hugo.
Next.JS kann dasselbe wie Gatsby/Hugo, bietet aber mehr Funktionen und basiert auf React.
Ich bin alt genug, um mich an die Zeiten zu erinnern, als der Server alles gerendert hat und CSS und JavaScript dazu da waren, die gerenderte Seite anzureichern.
Das Web ist ein sehr düsterer und overengineerter Ort geworden.
Fast unglaublich.
Deshalb baue ich meine Apps so: zuerst Server-Rendering, später anreichern.
Einklappbare Dropdowns oder Drag-and-drop mit jQuery sind nette Features, aber ich erinnere mich auch noch sehr deutlich an die State-Management-Hölle aus der JS/jQuery-Zeit und möchte dorthin nicht zurück.
Nur Spaß: Meine erste Geocities-Seite war HTML mit Dingen wie einem Besucherzähler oder
marquee.Auch meine erste PHP-Anwendung/mein erstes PHP-Projekt in der Schule nutzte noch kein JS; für statische Menüs und Header verwendete ich Frames, und Daten gingen einfach per Formular-Submit ans Backend.
Solche Zeiten gab es.
In meinem ersten einjährigen Praktikum im Rahmen des Studiums verwendeten wir ein Java-Backend, JSX-Templates in der Darstellungsschicht und PrototypeJS für Dinge wie Dialoge oder animierte Akkordeons.
Animation bedeutete damals: „die Höhe dieses Elements ein paar Mal pro Sekunde ändern“.
In meinem ersten Job schrieb ich viel JS, das Seiten mit Dingen wie „In den Warenkorb legen“ oder Bildkarussells anreicherte; das war die jQuery-Ära.
Im nächsten Job baute ich mit BackboneJS ziemlich miserabel eine UI, in der Support-Mitarbeiter in SAP-ähnliche Dinge schauen konnten.
Danach ging es ebenfalls darum, ein Investmentbanking-Frontend für Kunden mit BackboneJS neu zu bauen.
Das war ein Anwendungsfall, der sehr gut zu dem passte, was man damals Single-Page Application nannte.
Suchmaschinenoptimierung war nicht nötig, reines Frontend-Rendering war schnell genug, es war API-zentriert, und damals begannen die Leute zu begreifen, dass man dieselbe API für Web und Mobile nutzen konnte.
Meiner Meinung nach waren Webentwicklungswerkzeuge nie besser als heute, und auch die User Experience hat sich über die Jahre enorm verbessert.
Was wir früher AJAX nannten, ist von einem netten Zusatz-Gimmick zu einem alltäglichen Grundbaustein in Form von Client Components und Single-Page Apps geworden.
Server sind weiterhin leistungsfähig, wenn man das will, aber für interaktive Apps wie Dashboards, Karten, Spiele, Foren, Office-Apps oder Online-IDEs sind starke clientseitige Fähigkeiten gut.
Dadurch konnten Alltags-Apps in großem Stil von maßgeschneiderten Desktop-Apps für jedes Betriebssystem auf eine universelle Plattform für alle Laptops und Desktops wandern.
Natürlich erforderte diese Macht auch mehr Komplexität.
Einen Blog oder eine Landingpage mit HTML/CSS zu schreiben, ist etwas ganz anderes, als eine vollständige Web-App zu schreiben.
Angular und React entstanden, um die Entwicklung von Apps zu unterstützen, die um ein Vielfaches komplexer waren als zuvor – zu einer Zeit, als die JS-Runtime und die Sprache selbst im Vergleich zu serverseitigen Sprachen noch deutlich primitiver waren.
In den späten 2010ern gab es eine wirklich schmerzhafte Phase, in der verschiedene JS-Frameworks jeweils nur sehr kleine Teile des Problems lösten.
Heute ist das weniger der Fall.
Next hat gewonnen und ist zum Default geworden, und das aus gutem Grund.
Es bietet für Apps mittlerer Komplexität eine passende Abstraktionsebene und erlaubt es, serverseitiges Rendering und clientseitige Seiten gut zu mischen.
React Server Components machen diese Unterscheidung zu einem saubereren First-Class-Konzept.
Allerdings ergibt das erst ab einer gewissen Komplexität Sinn.
Wenn man es nicht braucht, muss man es nicht verwenden.
Für einen größtenteils statischen Blog oder eine Dokumentationsseite gibt es einfachere Architekturen.
Man kann weiterhin HTML schreiben und nach Bedarf ein paar Zeilen JS einstreuen, und für die meisten kleinen Unternehmen sind auch WordPress oder Wix möglich.
Wenn man aber komplexere Apps baut, ist React im Vergleich zu dem alten Ansatz wirklich ein Traum, bei jeder kleinen Interaktion zum Server zurückzugehen, die UI neu zu berechnen und jedes Mal die komplette HTML-Seite zu schicken.
Dieser Ansatz führte dazu, dass Kontext, Position auf der Seite und halb ausgefüllte Formulare verloren gingen, er ermutigte dazu, Formulardaten als State zu benutzen, und oft verlor man Arbeit, wenn man versehentlich auf Zurück klickte oder – bevor einfache Cloud-Skalierung verfügbar war – Server häufig ausfielen.
Meiner Ansicht nach ist es nur dann Overengineering, wenn es falsch eingesetzt wird.
In den passenden Anwendungsfällen sind diese Werkzeuge wirklich nützlich und manchmal unverzichtbar.
Der bedauerliche Teil ist vielleicht, dass sie zu oft gelehrt und ihr Einsatz auch in Situationen gefördert wird, in denen sie nicht nötig oder sogar schädlich sind.
Am Ende sollte man das passende Werkzeug für die Aufgabe verwenden.
Ich will React nicht gegenüber Vue, Svelte oder HTMX pushen; ich meine nur, dass clientseitige Komplexität ebenfalls ihren Nutzen hat.
Ich habe den Eindruck, dass React versucht, modernere, einfachere, schnellere und günstigere Alternativen einzuholen.
Statt aber die grundlegenden Probleme – Re-Rendering, häufig nötige Memoization und leaky Abstractions – zu beheben, wird React immer komplexer.
Wenn das Endergebnis großartig wäre, könnte ich den Aufwand verstehen, aber das ist es nicht.
React ist in realen Umgebungen langsamer, als Benchmarks vermuten lassen, und Next ist noch schlimmer.
In letzter Zeit habe ich viele sehr langsame Websites gesehen, die mit Next gebaut wurden.
Ich verstehe es wirklich nicht.
Wenn das React-Team React verbessern will, muss es den Kern reparieren.
Inzwischen gibt es so viele Abhängigkeiten im Ökosystem, dass alles kaputtgehen würde.
Target.com, Walmart.com, Microsoft Teams und unzählige andere Sites verwenden React.
Dazu kommen ein riesiges Komponenten-Ökosystem und Unternehmen, die darauf aufgebaut sind.
Die Kernkonzepte sind kaputt, aber sie zu reparieren würde bedeuten, potenziell alles andere kaputtzumachen.
Wenn man ohnehin alles kaputtmacht, ist es besser, etwas anderes zu verwenden.
Derzeit ist man durch die Masse der Abhängigkeiten an React gebunden und muss damit weiterrollen.
React rendert standardmäßig neu und man muss sich herausoptieren, während Vue, Solid, Preact und Svelte alle nur dort einsteigen, wo es nötig ist.
Das ist einer der Hauptgründe, warum es schwer korrekt zu verwenden und anfällig für bestimmte Arten von Bugs ist.
Oberflächlich sieht es wie normales JavaScript aus, aber man muss ständig darauf achten, ob man sich herausoptieren muss; in anderen Frameworks sind solche Bugs selten oder kommen fast gar nicht vor.
https://react.dev/blog/2023/03/22/react-labs-what-we-have-be...
Ich verstehe nicht, warum man jetzt wieder React im Backend verwendet, um HTML zu rendern
Wollen wir etwa 10 Jahre zurück?
Ich wechsle heutzutage oft zwischen Svelte und Django-Templates, und allein dass Svelte das DOM kennt, macht die Erfahrung deutlich besser
So etwas habe ich in einem Template-System, das nicht JS ist, noch nie gesehen
PHP und jQuery usw. habe ich ebenfalls erlebt
Außerdem ist es viel einfacher, die gesamte HTML-Erzeugung an einem Ort zu halten, wenn das Frontend React ist
Dazu kommt noch Unterstützung für statische Typisierung
Ich will RSC oder React nicht als die beste Lösung aller Zeiten verteidigen, aber einige der Gegenargumente hier sind unausgereift
Die Vorteile von React/RSC sind technisch nicht dasselbe wie wenn ein Server HTML/CSS und etwas JavaScript zurückgibt
Es bleibt eine einzige App, und im Vergleich zu SSR/Hydration ist es ein intelligenterer Umgang mit der Client/Server-Grenze
Ich würde gerne fundiertere Einwände dazu lesen, ob React sich selbst in eine Sackgasse designt hat und welche Auswege es gibt, aber zu PHP zurückzukehren ist keine Antwort
React ist auch nicht so schwer zu lernen, und es gibt einen Grund, warum selbst Nicht-Entwickler nach ein paar Wochen Bootcamp die Grundlagen beherrschen
JSX ist den Template-Systemen von Django, PHP und Rails objektiv überlegen
Bei der Hälfte der hingeworfenen Gegenargumente habe ich den Eindruck, dass die Leute ihre eigenen Projekte nicht einmal mit etwas wie Lighthouse gebenchmarkt haben