[HN Gopher] JSX over the Wire
___________________________________________________________________
JSX over the Wire
Author : danabramov
Score : 234 points
Date : 2025-04-15 15:56 UTC (1 days ago)
(HTM) web link (overreacted.io)
(TXT) w3m dump (overreacted.io)
| spellboots wrote:
| This feels a lot like https://inertiajs.com/ which I've really
| been enjoying using recently
| chrisvenum wrote:
| I am a huge fan of Inertia. I always felt limited by Blade but
| drained by the complexity of SPAs. Inertia makes using
| React/Vue feel as simple as old-school Laravel app. Long live
| the monolith.
| danabramov wrote:
| Yeah, there is quite a bit of overlap!
| tillcarlos wrote:
| This. We started using it with Rails and it's been great.
|
| I do like scrappy rails views that can be assembled fast - but
| the React views our FE dev is putting on top of existing rails
| controllers have a much better UX.
| motoboi wrote:
| Step by step coming back go JSF.
| Tade0 wrote:
| Or back to its PHP roots.
| danabramov wrote:
| Here's a section for you: https://overreacted.io/jsx-over-
| the-wire/#php-and-xhp
| merb wrote:
| or webforms, I hate it.
| cstew913 wrote:
| We don't have to go crazy. Let's just meet at MVC and call it
| a day, deal?
| altbdoor wrote:
| IMO this feels like Preact "render to string" with Express,
| though I might be oversimplifying things, and granted it wouldn't
| have all the niceties that React offers.
|
| Feels like HTMX, feels like we've come full circle.
| danabramov wrote:
| In my checklist (https://overreacted.io/jsx-over-the-
| wire/#dans-async-ui-fram...), that would satisfy only (2), (3)
| if it supports async/await in components, and (4). It would not
| satisfy (1) or (5) because then you'd have to hydrate the
| components on the client, which you wouldn't be able to do with
| Preact if they had server-only logic.
| altbdoor wrote:
| Thanks for the reply Dan. That was a great write up, if I
| might add.
|
| And yeap, you're right! If we need a lot more client side
| interactivity, just rendering JSX on server side won't cut
| it.
| skydhash wrote:
| Everything old is new again, and I'm not even that old to know
| that you can return HTML fragments from AJAX call. But this is
| worse from any architectural point view. Why?
|
| The old way was to return HTML fragments and add them to the DOM.
| There was still a separation of concern as the presentation layer
| on the server didn't care about the interface presented on the
| client. It was just data generally composed by a template
| library. The advent of SPA makes it so that we can reunite the
| presentation layer (with the template library) on the frontend
| and just send the data to be composed down with the request's
| response.
|
| The issue with this approach is to again split the frontend, but
| now you have two template libraries to take care of (in this case
| one, but on the two sides). The main advantages of having a
| boundary is that you can have the best representation of data for
| each side's logic, converting only when needs. And the conversion
| layer needs to be simple enough to not introduce complexity of
| its own. JSON is fine as it's easy to audit a parser and HTML is
| fine, because it's mostly used as is on the other layer. We also
| have binary representation, but they also have strong arguments
| for their use.
|
| With JSX on the server side, it's abstraction when there's no
| need to be. And in the wrong place to boot.
| tshaddox wrote:
| > The old way was to return HTML fragments and add them to the
| DOM. There was still a separation of concern as the
| presentation layer on the server didn't care about the
| interface presented on the client.
|
| I doubt there were many systems where the server-generated HTML
| fragments were generic enough that the server and client HTML
| documents didn't need to know anything about each other's HTML.
| It's conceivable to build such a system, particularly if it's
| intended for a screen-reader or an _extremely_ thinly-styled
| web page, but in either of those cases HTML injection over AJAX
| would have been an unlikely architectural choice.
|
| In practice, all these systems that did HTML injection over
| AJAX _were_ tightly coupled. The server made strong assumptions
| about the HTML documents that would be requesting HTML
| fragments, and the HTML documents made strong assumptions about
| the shape of the HTML fragments the server would give it.
| skydhash wrote:
| > _where the server-generated HTML fragments were generic
| enough that the server and client HTML documents didn 't need
| to know anything about each other's HTML._
|
| > _all these systems that did HTML injection over AJAX were
| tightly coupled_
|
| That's because the presentation layer originated on the
| server. What the server didn't care about was the
| transformation that alters the display of the HTML on the
| client. So you can add add an extension to your browser that
| translate the text to another language and it wouldn't matter
| to the server. Or inject your own styles. Even when you do an
| AJAX request, you can add JS code that discards the response.
| danabramov wrote:
| It feels like you haven't read the article and commented on the
| title.
|
| _> The old way was to return HTML fragments and add them to
| the DOM._
|
| Yes, and the problem with that is described at the end of this
| part: https://overreacted.io/jsx-over-the-wire/#async-xhp
|
| _> JSON is fine [..] With JSX on the server side, it's
| abstraction when there's no need to be. And in the wrong place
| to boot._
|
| I really don't know what you mean; the transport literally is
| JSON. We're not _literally_ sending JSX anywhere. That 's also
| in the article. The JSON output is shown about a dozen times
| throughout, especially in the third part. You can search for
| "JSON" on the page. It appears 97 times.
| whalesalad wrote:
| to be fair this post is enormous. if i were to try and print
| it on 8.5x11 it comes out to 71 pages
| danabramov wrote:
| I mean sure but not commenting is always an option. I don't
| really understand the impulse to argue with a position not
| expressed in the text.
| phpnode wrote:
| it happens because people really want to participate in
| the conversation, and that participation is more
| important to them than making a meaningful point.
| pixl97 wrote:
| Yet because of that the issue they were concerned about
| was shown to the thread readers without having to read 75
| pages of text.
|
| Quite often people read the form thread first before
| wasting their life on some large corpus of text that
| might be crap. High quality discussions can point out
| poor quality (or at least fundamentally incorrect) posts
| and the reasons behind them enlightening the rest of the
| readers.
| pier25 wrote:
| Maybe add a TLDR section?
| danabramov wrote:
| I don't think it would do justice to the article. If I
| could write a good tldr, I wouldn't need to write a long
| article in the first place. I don't think it's important
| to optimize the article for a Hacker News discussion.
|
| That said, I did include recaps of the three major
| sections at their end:
|
| - https://overreacted.io/jsx-over-the-wire/#recap-json-
| as-comp...
|
| - https://overreacted.io/jsx-over-the-wire/#recap-
| components-a...
|
| - https://overreacted.io/jsx-over-the-wire/#recap-jsx-
| over-the...
| pier25 wrote:
| Look, it's your article Dan, but it would be in your best
| interest to provide a tldr with the general points. It
| would help so that people don't misjudge your article
| (this has already happened). It could maybe make the
| article more interesting to people that initially
| discarded reading something so long too. And providing
| some kind of initial framework might help following along
| the article too for those that are actually reading it.
| yanndinendal wrote:
| The 3 tl;dr he just linked seem fine.
| pier25 wrote:
| the fact that he needed to link to those in a HN comment
| proves my point...
| swyx wrote:
| it really doesn't. stop trying to dumb him down for your
| personal tastes. he's much better at this than the rest
| of us
| owebmaster wrote:
| > he's much better at this than the rest of us
|
| That is not a good reason to make the content
| unnecessarily difficult for its target audience. Being
| smart also means being able to communicate with those who
| aren't as brilliant (or just don't have the time).
| pier25 wrote:
| > _stop trying to dumb him down for your personal tastes_
|
| That's unfair.
|
| If anything you're the one dumbing down what I wrote for
| _your_ personal taste.
| rwieruch wrote:
| Feed it to a LLM and let it give you the gist :)
| skydhash wrote:
| From the article: Replacing innerHTML wasn't
| working out particularly well--especially for the highly
| interative Ads product--which made an engineer (who was not
| me, by the way) wonder whether it's possible to run an XHP-
| style "tags render other tags" paradigm directly on the
| client computer without losing state between the re-renders.
|
| HTML is still a document format, and while there's a lot of
| features added to browsers over the year, we still have this
| as the core of any web page. It's always a given that state
| don't survive renders. In desktop software, the process is
| alive while the UI is shown, so that's great for having
| state, but web pages started as documents, and the API
| reflects that. So saying that it's an issue, it's the same as
| saying a fork is not great for cutting.
|
| React is an abstraction over the DOM for having a better API
| when you're trying not to re-render. And you can then
| simplify the format for transferring data between server and
| client. Net win on both side.
|
| But the technique described in the article is like having an
| hammer and seeing nails everywhere. I don't see the
| advantages of having JSX representation of JSON objects on
| the server side.
| danabramov wrote:
| _> I don't see the advantages of having JSX representation
| of JSON objects on the server side._
|
| That's not what we're building towards. I'm just using
| "breaking JSON apart" as a narrative device to show that
| Server Components componentize the UI-specific parts of the
| API logic (which previously lived in ad-hoc ViewModel-like
| parts of REST responses, or in the client codebase where
| REST responses get massaged).
|
| The change-up happens at this point in the article:
| https://overreacted.io/jsx-over-the-wire/#viewmodels-
| revisit...
|
| If you're interested in the "final" code, it's here:
| https://overreacted.io/jsx-over-the-wire/#final-code-
| slightl....
|
| It blends the previous "JSON-building" into components.
| skydhash wrote:
| I'm pointing out that this particular pattern (Server
| Components) is engendering more complexity than
| necessary.
|
| If you have a full blown SPA on the client side, you
| shouldn't use ViewModels as that will ties your backend
| API to the client. If you go for a mixed approach, then
| your presentation layer is on the server and it's not an
| API.
|
| HTMX is cognizant of this fact. What it adds are useful
| and nice abstractions on the basis that the interface is
| constructed on one end and used on the other. RSC is a
| complex solution for a simple problem.
| danabramov wrote:
| _> you shouldn't use ViewModels as that will ties your
| backend API to the client._
|
| It doesn't because you can do this as a layer in front of
| the backend, as argued here: https://overreacted.io/jsx-
| over-the-wire/#backend-for-fronte...
|
| Note "instead of replacing your existing REST API, you
| can add...". It's a thing people do these days!
| Recognizing the need for this layer has plenty of
| benefits.
|
| As for HTMX, I know you might disagree, but I think it's
| actually very similar in spirit to RSC. I do like it.
| Directives are like very limited Client components,
| server partials of your choice are like very limited
| Server components. It's a good way to get a feel for the
| model.
| megaman821 wrote:
| With morphdom (or one day native DOM diffing), wouldn't
| HTMX fufill 80% of your wishlist?
|
| I personally find HTMX pairs well with web components for
| client components since their lifecycle runs
| automatically when they get added to the DOM.
| pier25 wrote:
| What if the internal state of the web component has
| changed?
|
| Wouldn't an HTMX update stomp over it and reset the
| component to its initial state?
| megaman821 wrote:
| Not when using morphdom or the new moveBefore method.
| Although you would have to give your element a stable id.
| pier25 wrote:
| Even when using shadow DOM?
|
| What about internal JS state that isn't reflected in the
| DOM?
| megaman821 wrote:
| If it is new to the DOM it will get added. If it is
| present in the DOM (based on id and other attributes when
| the id is not present) it will not get recreated. It may
| be left alone or it may have its attributes merged. There
| are a ton of edge cases though, which is why there is no
| native DOM diffing yet.
| rapnie wrote:
| > Everything old is new again
|
| An age ago I took interest in KnockoutJS based on Model-View-
| ViewModel and found it pragmatic and easy to use. It was
| however at the beginning of the mad javascript framework-
| hopping marathon, so it was considered 'obsolete' after a few
| months. I just peeked, Knockout still exists.
|
| https://knockoutjs.com/
|
| Btw, I wouldn't hop back, but better hop forward, like with
| Datastar that was on HN the other day:
| https://news.ycombinator.com/item?id=43655914
| tshaddox wrote:
| Knockout was a huge leap in developer experience at the time.
| It's worth noting that Ryan Carniato, the creator of SolidJS,
| was a huge fan of Knockout. It's a major influence of
| SolidJS.
| kilroy123 wrote:
| I was a big fan of knockoutjs back in the day! An app I built
| with it is _still_ in use today.
| aylmao wrote:
| > The main advantages of having a boundary is that you can have
| the best representation of data for each side's logic,
| converting only when needs.
|
| RSC doesn't impede this. In fact it improves it. Instead of
| having your ORM's objects, to be converted to JSON, sent,
| parsed, and finally manipulated to your UIs needs, you skip the
| whole "convert to JSON" part. You can go straight from your ORM
| objects (best for data operations) to UI (best for rendering)
| and skip having to think about how the heck you'll serialize
| this to be serialized over the wire.
|
| > With JSX on the server side, it's abstraction when there's no
| need to be. And in the wrong place to boot.
|
| JSX is syntactic sugar for a specific format of JavaScript
| object. It's a pretty simple format really. From
| ReactJSXElement.js, L242 [1]: element = {
| // This tag allows us to uniquely identify this as a React
| Element $$typeof: REACT_ELEMENT_TYPE, //
| Built-in properties that belong on the element type,
| key, ref, props, };
|
| As far as I'm aware, TC39 hasn't yet specified which shape of
| literal is "ok" and which one is "wrong" to run on a computer,
| depending on wether that computer has a screen or not. I
| imagine this is why V8, JSC and SpiderMonkey, etc let you
| create objects of any shape you want on any environment. I
| don't understand what's wrong about using this shape on the
| server.
|
| [1]
| https://github.com/facebook/react/blob/e71d4205aed6c41b88e36...
| jdkoeck wrote:
| > Instead of having your ORM's objects, to be converted to
| JSON, sent, parsed, and finally manipulated to your UIs
| needs, you skip the whole "convert to JSON" part. You can go
| straight from your ORM objects (best for data operations) to
| UI (best for rendering) and skip having to think about how
| the heck you'll serialize this to be serialized over the
| wire.
|
| I can't let go of the fact that you get the exact same thing
| if you just render html on the server. It's driving me crazy.
| We've really gone full circle, and I'm not sure for what
| benefit.
| low_tech_punk wrote:
| The X in JSX stands for HTMX.
| recursivedoubts wrote:
| unfathomably based
| scop wrote:
| I can't help but read this in a baritone blustering-with-
| spittle transatlantic voice.
| danabramov wrote:
| Yes
| gherkinnn wrote:
| There is a part of my brain that is intrigued by React Server
| Components. I kinda get it.
|
| And yet, I see nothing but confusion around this topic. For two
| years now. I see Next.js shipping foot guns, I see docs on these
| rendering modes almost as long as those covering all of Django,
| and I see blog lengthy blog posts like this.
|
| When the majority of problems can be solved with Django, why tie
| yourself in to knots like this? At what point is it worth it?
| danabramov wrote:
| I think the rollout is a bit messy (especially because it
| wasn't introduced as a new thing but kind of replaced an
| already highly used but different thing). There are pros and
| cons to that kind of rollout. The tooling is also yet to
| mature. And we're still figuring out how to educate people on
| it.
|
| That said, I also think the basic concepts or RSC itself (not
| "rendering modes" which are a Next thing) are very simple and
| "up there" with closures, imports, async/await and structured
| programming in general. They deserve to be learned and broadly
| understood.
| alejalapeno wrote:
| I've represented JSX/the component hierarchy as JSON for CMS
| composition of React components. If you think of props as CMS
| inputs and children as nesting components then all the
| CMS/backend has to do is return the JSON representation and the
| frontend only needs to loop over it with React.createElement().
| wild_egg wrote:
| Deja vu with this blog. Another overengineered abstraction
| recreating things that already exist.
|
| Misunderstanding REST only to reinvent it in a more complex way.
| If your API speaks JSON, it's not REST unless/until you jump
| through all of these hoops to build a hypermedia client on top of
| it to translate the bespoke JSON into something meaningful.
|
| Everyone ignores the "hypermedia constraint" part of REST and
| then has to work crazy magic to make up for it.
|
| Instead, have your backend respond with HTML and you get
| everything else out of the box for free with a real REST
| interface.
| danabramov wrote:
| _> Another overengineered abstraction recreating things that
| already exist._
|
| This section is for you: https://overreacted.io/jsx-over-the-
| wire/#html-ssi-and-cgi
|
| _> Everyone ignores the "hypermedia constraint" part of REST
| and then has to work crazy magic to make up for it._
|
| Right, that's why I've linked to https://htmx.org/essays/how-
| did-rest-come-to-mean-the-opposi... the moment we started
| talking about this. The post also clarifies multiple times that
| I'm talking about how REST is used in practice, not its
| "textbook" interpretation that nobody refers to except in these
| arguments.
| wild_egg wrote:
| > This section is for you: https://overreacted.io/jsx-over-
| the-wire/#html-ssi-and-cgi
|
| Strawmanning the alternative as CGI with shell scripts really
| makes the entire post that much weaker.
|
| > nobody refers to except in these arguments.
|
| Be the change, maybe? People use REST like this because
| people write articles like this which uses REST this way.
| danabramov wrote:
| _> Strawmanning the alternative as CGI with shell scripts
| really makes the entire post that much weaker._
|
| I wasn't trying to strawman it--I was genuinely trying to
| show the historical progression. The snark was intended for
| the likely HN commenter who'd say this without reading, but
| the rest of the exploration is sincere. I tried to do it
| justice but lmk if I missed the mark.
|
| _> Be the change, maybe?_
|
| That's what I'm trying to do :-) This article _is_ an
| argument for hypermedia as the API. See the shape of
| response here: https://overreacted.io/jsx-over-the-
| wire/#the-data-always-fl...
|
| I think I've sufficiently motivated why that response isn't
| HTML originally; however, it _can_ be turned into HTML
| which is also mentioned in the article.
| timw4mail wrote:
| The hypermedia constraint is crazy magic itself. It's not like
| HATEOAS is fewer steps on the application and server side.
| aylmao wrote:
| We already have a way one way to render things on the browser,
| everyone. Wrap it up, there's definitely no more to explore
| here.
|
| And while we're at it, I'd like to know, why are people still
| building new and different game engines, programming languages,
| web browsers, operating systems, shells, etc, etc. Don't they
| know those things already exist?
|
| /s
|
| Joking aside, what's wrong with finding a new way of doing
| something? This is how we learn and discover things.
| nop_slide wrote:
| Just use Django/HTMX, Rails/Hotwire, or Laravel/Livewire
| pier25 wrote:
| Phoenix/Liveviews
|
| Fresh/Partials
|
| Astro/HTMX with Partials
| cpursley wrote:
| LiveView is the OG and absolutely smokes those in terms of
| performance (and DX), but ecosystem is lacking. Anyways, I'd
| rather use full stack React/Typescript over slow and untyped
| Rails or Python and their inferior ORMs.
| jauntywundrkind wrote:
| Dan Abramov (author) also recently wrote a related post, _React
| for Two Computers_.
|
| https://overreacted.io/react-for-two-computers/
| https://news.ycombinator.com/item?id=43631004 (66 points, 6 days
| ago, 54 comments)
| cstew913 wrote:
| It reminds me of when I sent HTML back from my Java Servlets.
|
| It's exciting to see server side rendering come back around.
| esco27 wrote:
| Yes, another case of old school web dev making a comeback. "HTML
| over the wire" is basically server-rendered templates (php, erb,
| ejs, jinja), sent asynchronously as structured data and
| interpreted by React to render the component tree.
|
| What's being done here isn't entirely new. Turbo/Hotwire [1],
| Phoenix LiveView, even Facebook's old Async XHP explored similar
| patterns. The twist is using JSX to define the component tree
| server-side and send it as JSON, so the view model logic and UI
| live in the same place. Feels new, but super familiar, even going
| back to CGI days.
|
| [1] https://hotwired.dev
| danabramov wrote:
| _> What's being done here isn't entirely new. Turbo/Hotwire
| [1], Phoenix LiveView, even Facebook's old Async XHP explored
| similar patterns._
|
| Right, that's why it's in the post: https://overreacted.io/jsx-
| over-the-wire/#async-xhp
|
| Likewise with CGI: https://overreacted.io/jsx-over-the-
| wire/#html-ssi-and-cgi
|
| Agree there's echoes of "old" in "new" but there are also
| distinct new things too :)
| gavmor wrote:
| Right? Right. I had similar thoughts (API that's the parent of
| the view? You mean _a controller_?), and quit very early into
| the post. Didn 't realize it was Dan Abramov, or I might've at
| least skimmed the 70% and 99% marks, but there's no going back
| now.
|
| Who is this written for? A junior dev? Or, are we minting
| senior devs with no historical knowledge?
| chacham15 wrote:
| The main thing that confuses me is that this seems to be PHP
| implemented in React...and talks about how to render the first
| page without a waterfall and all that makes sense, but the main
| issue with PHP was that reactivity was much harder. I didnt see /
| I dont understand how this deals with that.
|
| When you have a post with a like button and the user presses the
| like button, how do the like button props update? I assume that
| it would be a REST request to update the like model. You could
| make the like button refetch the like view model when the button
| is clicked, but then how do you tie that back to all the other UI
| elements that need to update as a result? E.g. what if the UI
| designer wants to put a highlight around posts which have been
| liked?
|
| On the server, you've already lost the state of the client after
| that first render, so doing some sort of reverse dependency trail
| seems fragile. So the only option would be to have the client do
| it, but then you're back to the waterfall (unless you somehow
| know the entire state of the client on the server for the server
| to be able to fully re-render the sub-tree, and what if multiple
| separate subtrees are involved in this?). I suppose that it is
| do-able if there exists NO client side state, but it still seems
| difficult. Am I missing something?
| danabramov wrote:
| _> When you have a post with a like button and the user presses
| the like button, how do the like button props update?_
|
| Right, so there's actually a few ways to do this, and the
| "best" one kind of depends on the tradeoffs of your UI.
|
| Since Like itself is a Client Component, it can just hit the
| POST endpoint and update its state locally. I.e. without
| "refreshing" any of the server stuff. It "knows" it's been
| liked. This is the traditional Client-only approach.
|
| Another option is to refetch UI from the server. In the
| simplest case, refetching the entire screen. Then yes, new
| props would be sent down (as JSON) and this would update both
| the Like button (if it uses them as its source of truth) _and_
| other UI elements (like the highlights you mentioned). It 'll
| just send the entire thing down (but it will be gracefully
| merged into the UI instead of replacing it). Of course, if your
| server always returns an unpredictable output (e.g. a Feed
| that's always different), then you don't want to do that. You
| could get more surgical with refreshing parts of the tree (e.g.
| a subroute) but going the first way (Client-only) in this case
| would be easier.
|
| In other words, the key thing that's different is that the
| client-side things are highly dynamic so they have agency in
| whether to do a client change surgically or to do a coarse
| roundtrip.
| no_wizard wrote:
| I believe there is a project (not sure if it's active) called
| JSX2 that treated this as exact problem as a first class concern.
| It was pretty fast too. Emulated the React API for the time quite
| well. This was 4-5 years ago at least
| jacobobryant wrote:
| The framework checklist[1] makes me think of Fulcro:
| https://fulcro.fulcrologic.com/. To a first approximation you
| could think of it like defining a GraphQL query alongside each of
| your UI components. When you load data for one component (e.g. a
| top-level page component), it combines its own query with the
| queries from its children UI components.
|
| [1] https://overreacted.io/jsx-over-the-wire/#dans-async-ui-
| fram...
| yawaramin wrote:
| I skimmed over this and imho it would be better to cut like 30%
| of the exposition and split it up into a series of articles
| tackling each style separately. Just my 2c.
| danabramov wrote:
| I'm hoping someone will do something like that. I try to write
| with the audience of writers in mind.
| android521 wrote:
| Very well written. It is rare to see these kinds of high quality
| articles these days.
| danabramov wrote:
| Thanks!
| wallrat wrote:
| Very well written (as expected) argument for RSC. It's
| interesting to see the parallels with Inertia.js.
|
| (a bit sad to see all the commenters that clearly haven't read
| the article though)
| jeppester wrote:
| I was immediately thinking of inertia.js.
|
| Inertia is "dumb" in that a component can't request data, but
| must rely on that the API knows which data it needs.
|
| RSC is "smarter", but also to it's detriment in my opinion. I
| have yet to see a "clean" Next project using RSC. Developers
| end up confused about which components should be what (and that
| some can be both), and "use client" becomes a crutch of sorts,
| making the projects messy.
|
| Ultimately I think most projects would be better off with
| Inertia's (BFF) model, because of its simplicity.
| dzonga wrote:
| inertia is the 'pragmatic' way. your controller endpoints in
| your backend - just pass the right amount of data to your
| inertia view.
|
| & every interaction is server driven.
| bk496 wrote:
| Another great post!
|
| I like the abstraction of server components but some of my co-
| workers seem to prefer HTMX (sending HTML rather than JSON) and
| can't really see any performance benefit from server components.
|
| Maybe OP could clear up - Whether HTML could be sent instead
| (depending on platform), there is a brief point about not losing
| state but if your component does not have input elements or can
| have it state thrown away then maybe raw HTML could work? - prop
| size vs markup/component size. If you send a component down with
| a 1:9 dynamic to static content component. Then wouldn't it be
| better to have the the 90% static preloaded in the client, then
| only 10% of the data transmitted? Any good heuristic options
| here? - "It's easy to make HTML out of JSON, but not the
| inverse". What is intrinsic about HTML/XML?
|
| --
|
| Also is Dan the only maintainer on the React team who does these
| kind of posts? do other members write long form. would be
| interesting to have a second angle.
| tbeseda wrote:
| A second angle from the same team?
|
| Or reference the 2+ decades written about the same pattern in
| simpler, faster, less complex implementations.
| mattbessey wrote:
| This was a really compelling article Dan, and I say that as a
| long time l advocate of "traditional" server side rendering like
| Rails of old.
|
| I think your checklist of characteristics frames things well. it
| reminds me of Remix's introduction to the library
|
| https://remix.run/docs/en/main/discussion/introduction > Building
| a plain HTML form and server-side handler in a back-end heavy web
| framework is just as easy to do as it is in Remix. But as soon as
| you want to cross over into an experience with animated
| validation messages, focus management, and pending UI, it
| requires a fundamental change in the code. Typically, people
| build an API route and then bring in a splash of client-side
| JavaScript to connect the two. With Remix, you simply add some
| code around the existing "server side view" without changing how
| it works fundamentally
|
| it was this argument (and a lot of playing around with
| challengers like htmx and JSX like syntax for Python / Go) that
| has brought me round to the idea that RSCs or something similar
| might well be the way to go.
|
| Bit of a shame seeing how poor some of the engagement has been on
| here and Reddit though. I thought the structure and length of the
| article was justified and helpful. Concerning how many peoples'
| responses are quite clearly covered in TFA they didn't read...
| swyx wrote:
| its absolutely ridiculous and sad the level of responses
| failing basic comprehension and this is a topic i happen to
| know well... makes you wonder how much to trust the avg hn
| comment where i am NOT knowledgeable...
| Vinnl wrote:
| There are a couple of "red flag" quips that if I hear them
| coming out of my mouth (or feel the urge to do so), I have to
| do a quick double take and reconsider my stance. "Everything
| old is new again" is one of them -- usually, that means I'm
| missing some of the progress that has happened in the meantime.
| parthdesai wrote:
| Not aware of remix, but how do you manage connection pooling,
| read vs write queries in these use cases?
| h14h wrote:
| Excellent read! This is the first time I feel like I finally have
| a good handle on the "what" & "why" of RSCs.
|
| It has also sparked a strong desire to see RSCs compared and
| contrasted with Phoenix LiveView.
|
| The distinction between RSCs sending "JSX" over the Wire, and
| LiveViews sending "minimal HTML diffs"[0] over the wire is
| fascinating to me, and I'm really curious how the two
| methodologies compare/contrast in practice.
|
| It'd be especially interesting to see how client-driven mutations
| are handled under each paradigm. For example, let's say an
| "onClick" is added to the `<button>` element in the `LikeButton`
| client component -- it immediately brings up a laundry list of
| questions for me:
|
| 1. Do you update the client state optimistically? 2. If you do,
| what do you do if the server request fails? 3. If you don't, what
| do you do instead? Intermediate loading state? 4. What happens if
| some of your friends submit likes the same time you do? 5. What
| if a user accidentally "liked", and tries to immediately "unlike"
| by double-clicking? 6. What if a friend submitted a like right
| after you did, but theirs was persisted before yours?
|
| (I'll refrain from adding questions about how all this would work
| in a globally distributed system (like BlueSky) with multiple
| servers and DB replicas ;))
|
| Essentially, I'm curious whether RSCs offer potential solutions
| to the same sorts of problems Jose Valim identified here[1] when
| looking at Remix Submission & Revalidation.
|
| Overall, LiveView & RSCs are easily my top two most exciting
| "full stack" application frameworks, and I love seeing how
| radically different their approaches are to solving the same set
| of problems.
|
| [0]: <https://www.phoenixframework.org/blog/phoenix-
| liveview-1.0-r...> [1]: <https://dashbit.co/blog/remix-
| concurrent-submissions-flawed>
| sophiebits wrote:
| React offers a useOptimistic Hook that is designed for client-
| side optimistic updates and automatically handles reverting the
| update upon failure, etc:
| https://react.dev/reference/react/useOptimistic
| rwieruch wrote:
| I have used RSCs only in Next.js, but to answer your questions:
|
| 1./2.: You can update it optimistically. [0]
|
| 3.: Depends on the framework's implementation. In Next.js,
| you'd invalidate the cache. [1][2]
|
| 4.: In the case of the like button, it would be a "form button"
| [3] which would have different ways [4] to show a pending
| state. It can be done with useFormStatus, useTransition or
| useActionState depending on your other needs in this component.
|
| 5.: You block the double request with useTransition [5] to
| disable the button.
|
| 6.: In Next, you would invalidate the cache and would see your
| like and the like of the other user.
|
| [0] https://react.dev/reference/react/useOptimistic
|
| [1] https://nextjs.org/docs/app/api-
| reference/functions/revalida...
|
| [2] https://nextjs.org/docs/app/api-reference/directives/use-
| cac...
|
| [3] https://www.robinwieruch.de/react-form-button/
|
| [4] https://www.robinwieruch.de/react-form-loading-pending-
| actio...
|
| [5] https://react.dev/reference/react/useTransition
| jonathanhefner wrote:
| RSC is indeed _very_ cool. It also serves as a superior
| serialization format compared to JSON. For example, it can
| roundtrip basic types such as `Date` and `Map` with no extra
| effort.
|
| One thing I would like to see more focus on in React is returning
| components from server functions. Right now, using server
| functions for data fetching is discouraged, but I think it has
| some compelling use cases. It is especially useful when you have
| components that need to fetch data dynamically, but you don't
| want the fetch / data tied to the URL, as it would be with a
| typical server component. For example, when fetching suggestions
| for a typeahead text input.
|
| (Self-promotion) I prototyped an API for consuming such
| components in an idiomatic way:
| https://github.com/jonathanhefner/next-remote-components. You can
| see a demo: https://next-remote-components.vercel.app/.
|
| To prove the idea is viable beyond Next.js, I also ported it to
| the Waku framework (https://github.com/jonathanhefner/twofold-
| remote-components) and the Twofold framework
| (https://github.com/jonathanhefner/twofold-remote-components).
|
| I would love to see something like it integrated into React
| proper.
| cadamsdotcom wrote:
| Really like this pattern, it's a new location of the curve of
| "how much rendering do you give the client". In the described
| architecture, JSX-as-JSON provides versatility once you've
| already shipped all the behavior to the client (a bunch of React
| components in a static JS that can be cached, the React Native
| example really demonstrated this well)
|
| One way to decide if this architecture is for you, is to consider
| where your app lands on the curve of "how much rendering code
| should you ship to client vs. how much unhydrated data should you
| ship". On that curve you can find everything from fully server-
| rendered HTML to REST APIs and everything in between, plus some
| less common examples too.
|
| Fully server-rendered HTML is among the fastest to usefulness -
| only relying on the browser to render HTML. By contrast in
| traditional React server rendering is only half of the story.
| Since after the layout is sent a great many API calls have to
| happen to provide a fully hydrated page.
|
| Your sweet spot on that curve is different for every app and
| depends on a few factors - chiefly, your app's blend of rate-of-
| change (maintenance burden over time) and its interactivity.
|
| If the app will not be interactive, take advantage of fully-
| backend rendering of HTML since the browser's rendering code is
| already installed and wicked fast.
|
| If it'll be highly interactive with changes that ripple across
| the app, you could go all the way past plain React to a
| Redux/Flux-like central client-side data store.
|
| And if it'll be extremely interactive client-side (eg. Google
| Docs), you may wish to ship all the code to the client and have
| it update its local store then sync to the server in the
| background.
|
| But this React Server Components paradigm is surprisingly suited
| to a great many CRUD apps. Definitely will consider it for future
| projects - thanks for such a great writeup!
| modal-soul wrote:
| I like this article a lot more than the previous one; not because
| of length.
|
| In the previous article, I was annoyed a bit by some of the
| fluffiness and redefinition of concepts that I was already
| familiar with. This one, however, felt much more concrete, and
| grounded in the history of the space, showing the tradeoffs and
| improvements in certain areas between them.
|
| The section that amounted to "I'm doing all of this other stuff
| just to turn it into HTML. With nice, functional, reusable JSX
| components, but still." really hit close to how I've felt.
|
| My question is: When did you first realize the usefulness of
| something like RSC? If React had cooked a little longer before
| gaining traction as the client-side thing, would it have been for
| "two computers"?
|
| I'm imagining a past where there was some "fuller stack" version
| that came out first, then there would've been something that
| could've been run on its own. "Here's our page-stitcher made to
| run client-side-only".
| acemarke wrote:
| Sounds like another one of Dan's talks, "React from Another
| Dimension", where he imagines a world in which server-side
| React came first and then extracted client functionality:
|
| - https://www.youtube.com/watch?v=zMf_xeGPn6s
| rwieruch wrote:
| Great talk, thanks for reminding me about this Mark!
| esprehn wrote:
| The big challenge with the approach not touched on in the post is
| version skew. During a deploy you'll have some new clients talk
| to old servers and some old clients talk to new servers. The
| ViewModel is a minimal representation of the data and you can
| constrain it with backwards compatibility guarantees (ex. Protos
| or Thrift), while the UI component JSON and their associated JS
| must be compatible with the running client.
|
| Vercel fixes this for a fee: https://vercel.com/docs/skew-
| protection
|
| I do wonder how many people will use the new React features and
| then have short outages during deploys like the FOUC of the past.
| Even their Pro plan has only 12 hours of protection so if you
| leave a tab open for 24 hours and then click a button it might
| hit a server where the server components and functions are
| incompatible.
| yawaramin wrote:
| Wouldn't this be easy to fix by injecting a a version number
| field in every JSON payload and if the expected version doesn't
| match the received one, just force a redirect/reload?
| tantalor wrote:
| Thrashing is why
| pfhayes wrote:
| Forcing a reload is a regression compared to the "standard"
| method proposed at the start of the article. If you have a
| REST API that requests attributes about a model, and the
| client is responsible for the presentation of that model,
| then it is much easier to support outdated clients (perhaps
| outdated by weeks or months, in the case of mobile apps)
| without interruption, because their pre-existing logic
| continues to work
| presentation wrote:
| Vercel's skew protection feature keeps old versions alive for
| a while and routes requests that come from an old client to
| that old version, with some API endpoints to forcibly kill
| old versions if need be, etc. I find it works reasonably
| well.
| AstroBen wrote:
| This all seems to be relatively simple concepts for an
| experienced programmer to understand, but it's being communicated
| in a very complex way due to the React world of JSX and
| Components
|
| What if we just talked about it _only_ in terms of simple data
| structures and function composition?
| valtism wrote:
| Really appreciate the quality you put into expressing these
| things. It was nice just to see a well laid-out justification of
| how trying to tie a frontend to a backend can get messy quickly.
| I'm definitely going to remember the "ungrounded abstraction" as
| a useful concept here.
| hcarvalhoalves wrote:
| > REST (or, rather, how REST is broadly used) encourages you to
| think in terms of Resources rather than Models or ViewModels. At
| first, your Resources start out as mirroring Models. But a single
| Model rarely has enough data for a screen, so you develop ad-hoc
| conventions for nesting Models in a Resource. However, including
| all the relevant Models (e.g. all Likes of a Post) is often
| impossible or impractical, so you start adding ViewModel-ish
| fields like friendLikes to your Resources.
|
| So, let's assume the alternative universe, where we did not mess
| up and got REST wrong.
|
| There's no constraint saying a resource (in the hypermedia sense)
| has to have the same shape as your business data, or anything
| else really. A resource _should_ have whatever representation is
| most useful to the client. If your language is "components"
| because you're making an interactive app - sure, go ahead and
| represent this as a resource. And we did that for a while, with
| xmlhttprequest + HTML fragments, and PHP includes on the server
| side.
|
| What we were missing all along was a way to decouple the browser
| from a single resource (the whole document), so we could have
| nested resources, and keep client state intact on refresh?
| yawaramin wrote:
| And this is exactly what we get with htmx.
| bastawhiz wrote:
| This article doesn't mention "event handlers" a single time. Even
| if you get past the client and server getting out of sync and
| addressing each component by a unique id that's stable between
| deploys (unless it's been updated), this article doesn't show how
| you might make any of these components interactive. You can't add
| an onClick on the server. The best I can figure, you pass these
| in with a context?
|
| Ultimately this really just smooshed around the interface without
| solving the problem it sets out to solve: it moves the formatting
| of the mail markup to the server, but you can't move all of it
| unless your content is entirely static (and if you're getting it
| from the server, SOMETHING has to be interactive).
| wonnage wrote:
| you put interactivity in client components, that seemed pretty
| clear to me
| bastawhiz wrote:
| And you just never have any handlers on the server
| components? The problem is that if a component is populated
| with data from the server, it's sending the data down as JSX.
| Which means _that component_ can 't react to interactivity of
| client components within it. Unless, of course, you draw the
| line further up and make more stuff client components.
|
| Consider making a list of posts from some sort of feed. If
| each item in the list is a server component, you can't have
| the component representing the item be a server component if
| you need to handle _any_ events in that item. So now you 're
| limited to just making the list component itself a server
| component. Well what good is that?
|
| The whole point of this is to move stuff off of the client.
| But it's not even clear that you're saving any bytes at all
| in this scenario, because if there's any props duplicated
| across items in the list, you've got to duplicate the data in
| the JSON: the shallower the returned JSX, the more raw data
| you send instead of JSX data. Which completely defats the
| point of going through all this trouble in the first place.
| rwieruch wrote:
| It's not really the scope of the article, but what about adding
| a client directive [0] and dropping in your event handler? Just
| like that, you're back in a familiar CSR React world, like in
| the "old" days.
|
| [0] https://react.dev/reference/rsc/use-client
| revskill wrote:
| The power is in react context for children to refer to parent
| state. Rsc completely solved the restful thesis. A rsc returns a
| spa with streaming data. It also solved the microfrontend
| architecturally. It is the end game.
|
| Spa developers missed the point totally by reinventing broken
| abstractions in their frameworks. The mising points is in code
| over convention. Stop enforcing your own broken convention and
| let developers use their own abstractions. Things are interpreted
| at runtime, not compile time. Bundler is for bundling, do not
| cross its boundary.
| csbartus wrote:
| What happened to the very elegant GraphQL? Where the client
| _declares_ its data needs, and _that's all_, all the rest is
| taken care by the framework?
|
| Compared to GraphQL, Server Components are a big step back: you
| have to do manually on the server what was given by default by
| GraphQL
| moi2388 wrote:
| N+1, security, authorisation, performance, caching, schema
| stitching..
| csbartus wrote:
| That's a backend issue I guess ...
| hyuuu wrote:
| N+1 is a solved problem at the framework level If GraphQL
| actually affects your performance, congratulations, your
| application is EXTREMELY popular, more so than Facebook, and
| they use graphql. There are also persisted queries etc.
|
| Not sure about caching, if anything, graphql offers a more
| granular level of caching so it can be reused even more?
|
| The only issue I see with graphql is the tooling makes it
| much harder to get it started on a new project, but the
| recent projects such as gql.tada makes it much easier, though
| still could be easier.
| rwieruch wrote:
| I have been out of touch with the GraphQL ecosystem for a
| while. What are the status quo solutions to the problems
| stated above?
|
| N+1 I just remember the dataloader
| https://github.com/graphql/dataloader Is it still used?
|
| What about the other things? I remember that Stitching and
| E2E type safety, for example, were pretty brittle in 2018.
| YuukiRey wrote:
| We use the dataloader pattern (albeit an in-house Golang
| implementation) and it has solved all our N+1 problems.
|
| E2E type safety in our case is handled by Typescript code
| generation. It works very well. I also happen to have to
| work in a NextJS codebase, which is the worst piece of
| technology I have ever had the displeasure of working
| with, and I don't really see any meaningful difference on
| a day to day basis between the type sharing in the NextJS
| codebase (where server/client is a very fuzzy boundary)
| and the other code base that just uses code generation
| and is a client only SPA.
|
| For stitching we use Nautilus and I've never observed any
| issues with it. We had one outage because of some
| description that was updated in some dependency and that
| sucked but for the most part it just works. Our usage is
| probably relatively simple though.
| rwieruch wrote:
| Thanks, really appreciate your reply!
| moi2388 wrote:
| Isn't every graphql a post, so no http response caching, so
| you need to do it in-app or with redis?
|
| N+1 and nested queries etc were still problems last I
| checked (few years ago).
|
| I'm sure there are solutions. Just that it's not as trivial
| as "use graphql" and your problems are solved.
|
| Please correct me if I'm wrong
| hyuuu wrote:
| I was just going to say, all of this has been solved with
| graphql, elegantly.
| anentropic wrote:
| Couldn't you have both?
|
| I assumed RSC was more concerned with which end did the
| rendering, and GraphQL with how to fetch just the right data in
| one request
| eadmund wrote:
| > the very elegant GraphQL
|
| The GraphQL which 'elegantly' returns a 200 on errors? The
| GraphQL which 'elegantly' encodes idempotent reads as mutating
| POSTS? The GraphQL which 'elegantly' creates its own _ad hoc_
| JSON-but-not-JSON language?
|
| The right approach, of course, is HTMX-style real REST
| (incidentally there needs to be a quick way to distinguish real
| REST from fake OpenAPI-style JSON-as-a-service). E.g., the
| article says: 'your client should be able to request all data
| for a specific screen at once.' Yes, of course: the way to
| request a page is to (wait for it, JavaScript kiddies):
| _request a page_.
|
| The even better approach is to advance the state of the art
| beyond JavaScript, beyond HTML and beyond CSS. There is no good
| reason for these three to be completely separate syntaxes.
| Fortunately, there is already a good universal syntax for trees
| of data: S-expressions. The original article mentions SDUI as
| 'essentially it's just JSON endpoints that return UI trees': in
| a sane web development model the UI trees would be
| S-expressions macro-expanded into SHTML.
| grncdr wrote:
| > Since XHP executes on a server that emits HTML, the most that
| you can do relatively seamlessly is to replace parts of an
| existing markup with the newly generated HTML markup from the
| server by updating innerHTML of some DOM node.
|
| It's a very long post so maybe I missed it, but does Dan ever
| address morphdom and its descendants? I feel like that's a very
| relevant point in the design space explored in the article.
| kassner wrote:
| I feel the article could have ended after Step 1. It makes the
| point that you don't have to follow REST and can build your own
| session-dependent API endpoints, and use them to fetch data from
| a component.
|
| I don't see a point in making that a server-side render. You are
| now coupling backend to frontend, and forcing the backend to do
| something that is not its job (assuming you don't do SSR
| already).
|
| One can argue that its useful if you would use the endpoint for
| ESI/SSI (I loved it in my Varnish days) but that's only a sane
| option if you are doing server-side renders for everything.
| Mixing CSR and SSR is OK, but that's a huge amount of extra
| complexity that you could avoid by just picking one, and
| generally adding SSRs is mostly for SEO-purposes, which session-
| dependent content is excluded anyway.
|
| My brain much prefers the separation of concerns. Just give me a
| JSON API, and let the frontend take care of representation.
| barrkel wrote:
| The point of doing a server-side render follows from two other
| ideas:
|
| * that the code which fetches data required for UI is much more
| efficiently executed on the server-side, especially when
| there's data dependencies - when a later bit of data needs to
| be fetched using keys loaded in a previous load
|
| * that the code which fetches and assembles data for the UI
| necessarily has the same structure as the UI itself; it is
| already tied to the UI semantically. It's made up out of front
| end concerns, and it changes in lockstep with the front end.
| Logically, if it makes life easier / faster, responsibility may
| migrate between the client and server, since this back end
| logic is part of the UI.
|
| The BFF thing is a place to put this on the server. It's
| specifically a back end service which is owned by the front end
| UI engineers. FWIW, it's also a pattern that you see a lot in
| Google. Back end services serve up RPC endpoints which are
| consumed by front end services (or other back end services).
| The front end service is a service that runs server-side, and
| assembles data from all the back end services so the client can
| render. And the front end service is owned by the front end
| team.
| moqizhengz wrote:
| BFF is in practice a pain in the ass, it is large enterprise
| like Google's compromise but many ppl are trying to follow
| what Google does without Google's problem scope and well-
| developed infra.
|
| Dan's post somehow reinforces the opinion that SSR frameworks
| are not full-stack, they can at most do some BFF jobs and you
| need an actual backend.
| barrkel wrote:
| The alternative really is as Dan says: you end up with a
| bunch of REST endpoints that either serve up too much, or
| have configuration flags to control how much they serve,
| simply to satisfy front end concerns while avoiding adding
| round trip latency. You see this in much smaller apps than
| Google scale. It's a genuine tension.
|
| Usually the endpoints get too fat, then there's a
| performance push to speed them up, then you start thinking
| about fat and thin versions. I've seen it happen
| repeatedly.
| curtisblaine wrote:
| Or you can have your "backend for frontend"... on the frontend,
| so you don't have an additional layer, it's always written in the
| frontend language and it's always synced to the frontend needs.
| The lengths we go to reinvent the squared wheel.
| hu3 wrote:
| Random JSX nugget:
|
| JSX is a descendant of a PHP extention called XHP [1] [2]
|
| [1] https://legacy.reactjs.org/blog/2016/09/28/our-
| first-50000-s...
|
| [2] https://www.facebook.com/notes/10158791323777200/
| zarzavat wrote:
| I'm annoyed to learn that even the original PHP version had
| `class=` working.
| MrJohz wrote:
| In fairness, `className` makes a lot of sense given that the
| native DOM uses the `className` attribute rather than
| `class`. In that sense, it's a consistent choice, just a
| consistent choice with the DOM rather than with HTML.
|
| The bigger issue is the changes to events and how they get
| fired, some of which make sense, others of which just break
| people's expectations of how Javascript should work when they
| move to non-React projects.
| littlecranky67 wrote:
| Preact fixed that years ago and you can just use class=
| Ambroos wrote:
| Internally at Facebook you could also just call React
| components from XHP. Not very relevant on what you see on
| Facebook now as a user, but in older internal tools built with
| XHP it made it very easy to just throw in React components.
|
| When you'd annotate a React component with ReactXHP (if I
| remember correctly), some codegen would generate an equivalent
| XHP components that takes the same props, and can just be used
| anywhere in XHP. It worked very well when I last used it!
|
| Slightly less related but still somewhat, they have an
| extension to GraphQL as well that allows you to call/require
| React components from within GraphQL. If you look at a random
| GraphQL response there's a good chance you will see things like
| `"__dr":
| "GroupsCometHighlightStoryAlbumAttachmentStyle.react"`. I never
| looked into the mechanics of how these worked.
| lioeters wrote:
| > you could also just call React components from XHP
|
| Fascinating, I didn't know there was such a close integration
| between XHP and React. I imagined the history like XHP being
| a predecessor or prior art, but now I see there was an
| overlap of both being used together, long enough to have
| special language constructs to "bind" the two worlds.
|
| "ReactXHP" didn't turn up anything, but XHP-JS sounds like
| it.
|
| > We have a rapidly growing library of React components, but
| sometimes we'll want to render the same thing from a page
| that is mostly static. Rewriting the whole page in React is
| not always the right decision, but duplicating the rendering
| code in XHP and React can lead to long-term pain.
|
| > XHP-JS makes it convenient to construct a thin XHP wrapper
| around a client-side React element, avoiding both of these
| problems. This can also be combined with XHPAsync to prefetch
| some data, at the cost of slightly weakening encapsulation.
|
| https://engineering.fb.com/2015/07/09/open-
| source/announcing...
|
| This is from ten years ago, and it's asking some of the same
| big questions as the posted article, JSX over the Wire. How
| to efficiently serve a mixture of static and dynamic content,
| where the same HTML templates and partials are rendered on
| server and client side. How to fetch, refresh data, and re-
| hydrate those templates.
|
| With this historical context, I can understand better the
| purpose of React Server Components, what it's supposed to
| accomplish. Using the same language for both client/server-
| side rendering solves a large swath of the problem space. I
| haven't finished reading the article, so I'll go enjoy the
| rest of it.
| icemelt8 wrote:
| I knew this post would eventually peddle me nextJS, and it did!
| brap wrote:
| Dan, I've been reading some of your posts and watching some of
| your talks since Redux, and I really love how passionate you are
| about this stuff. I think the frontend world is lucky to have
| someone like you who spends a lot of time thinking about these
| things enthusiastically.
|
| Anyway, it's hard to deny that React dev nowadays is an ugly
| mess. Have you given any thought to what a next-gen framework
| might look like (I'm sure you have)?
| aabbcc1241 wrote:
| Hey, thanks for sharing "JSX Over the Wire"! As the creator of
| ts-liveview, I'm thrilled to see Dan's ideas on server-side JSX
| rendering and minimal client updates--they mesh so well with my
| work.
|
| ts-liveview is a TypeScript framework I built (grab it as a
| starter project on GitHub[1]) for real-time, server-rendered
| apps. It uses JSX/TSX to render HTML server-side and, in
| WebSocket mode, updates the DOM by targeting specific CSS
| selectors (document.querySelector) over WebSockets or HTTP/2
| streaming. This keeps client-side JavaScript light, delivering
| fast, SEO-friendly pages and reactive UIs, much like Dan's "JSX
| over the wire" vision.
|
| What's your take on this server-driven approach? Could it shake
| up how we build apps compared to heavy client-side frameworks?
| Curious if you've tried ts-liveview yet--it's been a fun project
| to dig into these ideas!
|
| [1] https://github.com/beenotung/ts-liveview
| _heimdall wrote:
| Is Dan reinventing Astro?
|
| The biggest draw that pulled me to Astro early on was the fact
| that it uses JSX for a, in my opinion, better server side
| templating system.
| lerp-io wrote:
| isn't this same thing as graphql?
| andrewstuart wrote:
| IMO:
|
| 1: APIs should return JSON because endpoints do often get reused
| throughout an application.
|
| 2: it really is super easy to get the JSON into client side HTML
| with JSX
|
| 3: APIs should not return everything needed for a component, APIs
| should return one thing only. Makes back and front end more
| simple and flexible and honestly who cares about the extra
| network requests
| _heimdall wrote:
| I always come back to the idea that I want to render HTML where
| the state lives rather than shipping both a rendering engine and
| all the necessary data to a client.
|
| In most cases that means rendering HTML on the server, where most
| of the data lives, and using a handful of small components in the
| frontend for state that never goes to the backend.
| MJGrzymek wrote:
| Reading the linked article https://htmx.org/essays/how-did-rest-
| come-to-mean-the-opposi... , does this mean Next.js is the real
| REST?
|
| I still can't get over how the "API" in "REST API" apparently
| originally meant "a website".
| agos wrote:
| some of the presented problems of the "good ol' REST endpoint"
| approach feel a tiny bit of a strawman, like "you can't add
| endpoints because /get/posts is taken", but having to cobble
| together a response from multiple calls (and all it entails, such
| as loading states) because is a very real and I feel very shared
| pain. And in my experience, too, GraphQL has been an
| unsatisfactory solution.
|
| A BFF is indeed a possible solution and yeah if you have a BFF
| made in JS for your React app the natural conclusion is that you
| might as well start returning JSX.
|
| But. BUT. "if you have a BFF made in JS" and "if your BFF is for
| your React app" are huge, huge ifs. Running another layer on the
| server just to solve this specific problem for your React app
| might work but it's a huge tradeoff and a non starter (or at
| least a very hard sale) for many teams; and this tradeoff is not
| stated, acknowledged, explored in any way in this writing (or in
| most writing pushing RSCs, in my experience).
|
| And a minor point but worth mentioning nonetheless, writing stuff
| like "Directly calling REST APIs from the client layer ignores
| the realities of how user interfaces evolve" sounds like the
| author thinks people using REST APIs are naive simpletons who are
| so unskilled they are missing a fundamental point of software
| development. People directly calling REST APIs are not cavemen,
| they know about the reality of evolving UI, they just chose a
| different approach to the problem.
| naasking wrote:
| > But putting ViewModels in Resources also doesn't work very
| well. ViewModels are not abstract concepts like "a post"; each
| ViewModel describes a specific piece of UI. As a result, the
| shape of your "Post" Resource grows to encompass the needs of
| every screen displaying a post.
|
| I don't see the issue with adding an endpoint per viewmodel.
| Treating viewmodels as resources seems perfectly fine. Then
| again, I'm already on the HATEOAS and HTMX bandwagon, so maybe
| that just seems obvious, as it's no worse than returning HTML or
| JSX that could be constantly changing. If you actually need
| stable API endpoints for others to consume for other purposes,
| that's a separate consideration. This seems to be the direction
| the rest of the article goes.
| williamcotton wrote:
| _We're in the nineties, okay?_
|
| Whee! #!/usr/bin/perl
| $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if
| ($ENV{'REQUEST_METHOD'} eq "GET") { $buffer =
| $ENV{'QUERY_STRING'}; } print "Content-type:
| text/html\n\n"; $post_id = $buffer; $post_id
| =~ s/&.*//; # Get first parameter (before any &) $post_id
| =~ s/[^a-zA-Z0-9\._-]//g; # Sanitize input
| $truncate = ($buffer =~ /truncateContent=true/) ? 1 : 0;
| $title = `mysql -u admin -p'password' -D blog --skip-column-names
| -e "SELECT title FROM posts WHERE url='$post_id'"`;
| chomp($title); $content = `mysql -u admin
| -p'password' -D blog --skip-column-names -e "SELECT content FROM
| posts WHERE url='$post_id'"`; chomp($content);
| if ($truncate) { # Extract first paragraph (everything
| before the first blank line) $first_paragraph =
| $content; $first_paragraph =~ s/\n\n.*//s;
| print "<h3><a href=\"/$post_id.html\">$title</a></h3>\n";
| print "<p>$first_paragraph [...]</p>\n"; } else {
| print "<h1>$title</h1>\n"; print "<p>\n";
| print "$content\n"; print "</p>\n"; }
___________________________________________________________________
(page generated 2025-04-16 17:02 UTC)