It's funny, as I could probably credit Dan with the reason I mostly spend time with Clojure and ClojureScript today. I think ClojureScript/Reagent/Om was mentioned really quickly when he did the "Hot Reloading / Time Traveling" talk back in 2014 sometime, which eventually led me to find Clojure which basically was made for making those things easy for the entire stack, not just frontend.
So thanks Dan for leading me to greener pastures, but a shame you still haven't taken the time to look into any lisp! Reagent+ClojureScript should be (relatively) familiar to you, as long as you get over the parenthesis-avoidance stage most of us go through :)
codr7 · 1d ago
Clojure is far from the whole truth when it comes to Lisp though.
Common Lisp doesn't have as many opinions about your code, includes several nice features that Clojure skipped, and isn't chained to the JVM.
diggan · 1d ago
> Clojure is far from the whole truth when it comes to Lisp though.
That's true for sure, and I'm sorry if my comment gave that impression, I'm not trying to say that Clojure is the only lisp, or even the best lisp! Just the one that fit me and my problems the best.
> and isn't chained to the JVM.
Neither is Clojure (the language), as it's available with JavaScript as a host (ClojureScript), LLVM (Jank) or even the Erlang VM (Clojerl). I'm sure there are more out there too, but the Clojure-JVM runtime isn't the only one available.
With that said, lots of people say Common Lisp is another good lisp, and been deployed in production for many decades, so I'm sure it's another great choice if anyone wanna get deeper into lisps. I personally haven't taken the time (yet!) to get to know it on any deeper level, so would be weird to recommend it before another lisp I know much better.
codr7 · 1d ago
Not at all, just a bit sad that so many good ideas are lost chasing the latest hype.
lucyjojo · 4h ago
clojure is almost 20 years old...
Capricorn2481 · 1d ago
Are we really calling Clojure the latest hype? It's not exactly new or even that popular. Or is everything that's not CL just hype?
Personally, I think it does a few things better than Common Lisp and many Clojurists came from Common Lisp.
snickerbockers · 1d ago
yeah but the real GOAT here is elisp. True enlightenment comes when LISP ceases to be a language and instead becomes a turing-complete configuration file wherein you routinely spend 4+ hours coaxing a text editor into doing things that would have been trivial if you had just used a well-known single-purpose program that came with your gnu/linux distro anyways. It's a thing of beauty when it finally works, so much so that it's almost worth getting yelled at by your boss for taking way too long to complete simple tasks.
To paraphrase the late, great President John F Kennedy, "We choose to use emacs not because it is easy but because it is hard. Because that goal will serve to organize and measure the best of our energies and skills because that challenge is one we are willing to accept, one we are unwilling to postpone, and one we intend to win!"
fp64 · 23h ago
I was consistently tempted to give emacs a fair try but after now more than 20 years of vim it got more and more difficult to even imagine betraying it. Thankfully, now with neovim I can spend hours in my config files, and with fennel I can even lisp.
I wonder what things would look like today if Netscape had stuck with its first idea of embedding Scheme instead of creating Javascript.
mighmi · 23h ago
Perhaps paradise. The browser as a lisp machine, ah... Dreams. The spritely team is making strides to using Guile in WASM, but it's nothing like s expr instead of JSON etc. could have been. https://files.spritely.institute/docs/guile-hoot/0.1.0/Intro...
potholereseller · 23h ago
It would probably depend on the Scheme/Lisp implementation and how it was secured.
If it used a Scheme implementation like in Halo:CE, then people would have justifiably hated it. If it used something more like MIT-Scheme, people might've been okay with it. But I suspect it would get the same hate that JS gets, since there is a lot of low-quality JS code floating around -- even though JS itself isn't remotely that bad -- and you would instead have a lot of low-quality Scheme code floating around. Damned if you do, damned if you don't.
FWIW, it is feasible to put Scheme/Lisp in a browser today, and it might even be fun. Take a browser that lacks JS (e.g. Dillo, w3m); figure out how to add Firefox's or Chromium's approach to isolating each Javascript instance; and embed a Scheme or Common Lisp implementation (e.g. Chez Scheme [1] or ECL [2]).
You will need to decide what Scheme/Lisp functions/macros to include/exclude. It may seem obvious to exclude file operations, but they did that with JS and now we have IndexedDB; a restricted, virtual file system might be fun to play with. Multithreading might seem like a great thing to include, until you start trying to implement secure multithreading. I would start with whatever cl-isolated [3] allows and expand/contract from there.
And before anyone asks, "would this actually be worth implementing in 2025?", the answer is decidely "yes". You could build powerful desktop applications without the full weight of Electron. You could develop local-network webapps for you and/or your company. But I think it would be a bad idea to deploy this on the open internet without first spending a lot of time securing the browser overall.
Another option is resurrecting Closure [4], which is written entirely in Common Lisp. In that, you could go on a wild tangent and support multiple scripting languages (e.g. Common Lisp via cl-isolated, cl-forth [5], cl-javascript [6], cl-python [7], scheme88 [8], and even Coalton [9]).
[2] With ECL, you could use cl-isolated in addition to OS-level containerization, to achieve more defense-in-depth. Or maybe port cl-isolated to Chez Scheme.
I imagine the sandboxing and existence of terrible code wouldn't have been especially different from JS. I think the ubiquity would have helped to make people more aware of the advantages of Lisp. We might have substantially more Lisp-derived languages in popular use today.
I'm currently working on a project in Clojurescript, and I'm aware of some of the other options for running Lisp in a browser.
kazinator · 23h ago
There would still be alternative languages in the browser ecosystem. Just they wouldn't have transpile to an idiotic target.
randomuxx · 1d ago
Maybe I'm slow, but after countless posts about RSC, I still don't get the appeal.
Is it really worth the headache and extra complexity?
Caveat: I've used Vue more than any other FE library/framework, but for the last 3 years I worked exclusively with React (via Next—app router).
The company I worked (I left in Jan) for jumped on this RSC train as soon as it was released and boy,oh boy was it a mess!
We ofteb got direct support from Vercel when our shit will break or not work as expected...
To say the app was slow and behaved unexpected would be an understatement.
Eventually, they had to rewrite everything back as a SPA.
danabramov · 1d ago
I think RSC itself is pretty solid by this point but frameworks around it (primarily Next.js) are still somewhat rough (and were much rougher during the initial App Router release). Hard to say more without knowing what kind of issues you were hitting.
I'm posting because I find the technology interesting. I don't have a goal of convincing you to use or adopt it. I sometimes write about specific aspects that I find appealing but YMMV.
randomuxx · 1d ago
Fair Dan, and I appreciate your response.
I also hope you understand I wrote this based on my experience with it. ♥
danabramov · 1d ago
Sure! Do you recall what kind of issues or bugs you were hitting?
pjmlp · 23h ago
That is exactly the point, due to trying to cater to the hype FE culture, many SaaS providers only make React and Next.js SDKs available for their products and extension points.
So just like it happens in some many cases in our fashion driven industry, we get dragged into using tools we don't agree with, or be busy with yak shaving adding support for other tooling.
kaoD · 1d ago
Maybe it's where I'm imagining we're headed (and not where we're actually headed) but I think it will bring us into the sweet spot that I want/need: good old PHP-like server-rendered sites (or even static pages) with custom interactive components (think e.g. forms with client-side validation) without the mess that mixing PHP+jQuery used to be.
Server rendering is enough for the 80% use case. Browsers are optimized for it. Sprinkle interactivity without the impedance mismatch of jQuery and you're in heaven. No more overengineered state syncing between client and server. Just. Fetch. HTML.
Currently frameworks are trying to shoehorn it into the 2018 React mindset but that's not what I think is needed for them to succeed.
math_dandy · 1d ago
I think RSC is trying to answer the question, “How can we make server rendering and sprinkles of interactivity composable?” What if you want your sprinkles to have server rendered content inside of them, each of which may contain other interactive/dynamic elements?
I posit that any composable version of sprinkles or the “island architecture” will closely resemble RSC.
Only a small fraction of apps will ever use the full power of the RSC architecture. However, the React team doesn’t build apps, they build primitives for building apps. And good primitives are composable.
owebmaster · 6h ago
Yeah that is the right answer imo.
What they did wrong tho was to morph React into this mess. RSC should be React Server and live along React DOM and React Native, something almost unrelated to the previous concept of React. But we got this an entangled mess.
skydhash · 1d ago
You either make presentation the server job or the client job. Spreading it between the two results in the same trouble that distributed systems are trying to solve to this day. At least backend have a reason for going the distributed route (resources and risk management).
kaoD · 1d ago
> You either make presentation the server job or the client job
Is that your axiom or do you have any justification? I just don't agree with it.
Why should the server know about a datepicker's internal details?
skydhash · 23h ago
It's all relate to consistency. If presentation is the job of the server (html templates), the server is the source of truth and the client state is expected to be transient. That is a good model for most web applications including this forums.
There's some case where local state is more important (figma, google maps, chat app) and the backend is expected to act as a data source with a domain-specific API. Any mixture between the two and you will make the separation between the two domain (server concerns and client concerns) at the wrong place, making the design more complex (however well you hide it behind the curtains).
kaoD · 23h ago
> If presentation is the job of the server (html templates), the server is the source of truth and the client state is expected to be transient.
Which is exactly why the client state should be transient non-application state like datepickers, dropdowns, text boxes, etc. and it does not belong in the server (essentially what jQuery was used for back in the day, interactive sprinkles). And the other way around.
Perhaps you agree with me but there was something lost in translation?
skydhash · 21h ago
Something was lost. I was arguing either send the presentation layer as data to the web browser as resources, or send data that from which the browser and the UI library (react, svelte,...) will derives the UI from.
RSC does a weird split where the engine is the same on both ends instead of a clear separation layer where one does not need to know about each other. I much prefer HTMX approach (samey old backend where you mostly take care of everything in the frontend) and Laravel Livewire approach (where you take care of everything backend side, with optional client side scripting).
No need to reinvent the world to fix a single problem.
owebmaster · 20h ago
You are right that there is no appeal. Besides the people pushing for it, which are related to the project, I've not see any project talking about the benefits of using it. React is consolidated but it doesn't mean the maintainers can evolve it the way they want. The push to RSC will undoubtedly kills React.
sktrdie · 1d ago
Will this whole idea of writing more server-side logic pay off?
I'm not sure. It felt like we were moving towards dumb backends that sync automatically towards frontends that would contain most logic. Things like https://localfirstweb.dev/ or https://electric-sql.com/ felt like the future
Writing more server code (as quoting/react-server-components are suggesting) will increase the surface area where errors can occur. Limiting that to either just the server/client feels like a much saner approach
danabramov · 1d ago
That's a good question! I'll maybe post some time about that. I don't think sync engines are "the future" although they have their uses. But if you care about large-scale aggregation, private data with sophisticated permission models, aggregation across private data, feeds, and such, server/client is a much more powerful model. For example, I don't think you can implement something like Twitter in a pure peer-to-peer fashion without compromising on functionality a lot.
qudat · 1d ago
> I don't think sync engines are "the future" although they have their uses
I think the same argument applies to RSC. For many use cases, it doesn't make sense. Many organizations and projects do not need SEO or server code specifically for their FE. If the organization has committed to an API service in order to support a range of clients then RSC/react server framework is "pure overhead."
As someone who has been building with React for a decade, RSC was the moment where I felt the complexity vastly outweighed the benefit. I'm in a position where I can argue that SPAs are dramatically simpler to implement compared to RSC/nextjs, which I think would be surprising to outsiders who bemoan SPAs as complex.
I'm not trying to get you or anyone to adopt RSC, I'm just trying to explain that if you're bought into the idea that a dedicated backend for your frontend is good (and there are plenty good reasons for people to come to this conclusion), there exists a way to structure the code of that backend that has interesting compositional properties.
I think that's a slightly different kind of message than "servers are unnecessary, peer-to-peer is the future". You can keep servers dumb, but some kinds of product features demand the servers to do the job. And then if you want to squeeze the most out of the server as it relates to your client app, RSC is one way to look at it.
Joeri · 21h ago
You can keep servers dumb, but some kinds of product features demand the servers to do the job. And then if you want to squeeze the most out of the server as it relates to your client app, RSC is one way to look at it.
I feel like the design space of making the server as dumb as possible is not sufficiently explored yet. I’m imagining PWAs that work offline by default, hosted on static hosting, talking to CORS-unlocked PKCE-authenticated APIs, storing their state as dumb files in APIs like dropbox, and doing all of the cross-client p2p syncing and merging client-side inside of a service worker.
It wouldn’t work for all categories of software, but so much productivity software ultimately reduces to a per-user file paradigm instead of a central database (outliners, notes, task managers, image editors, …) that I think a lot of complex web apps could be built this way. They wouldn’t work well on low end android phones, but then most of the products from those categories already don’t work well there, when half their logic is still on the server.
And yes, I know, Apple does not play nice with PWAs, but I still think there’s something there that I wish more people would explore.
flufluflufluffy · 1d ago
It’s less “RSC for Lisp Developers” and more “‘use client’ for people who know what strings are” xD
danabramov · 1d ago
Maybe somewhere in the middle? :) "use client" is more first-class than wrapping code in a string because it gives you an opaque reference to the module and its dependencies in a way that gets seamlessly unwrapped on the other machine. It doesn't really feel like dealing with strings because it's integrated with the module system. But yes, it's opaque unless quoting.
Philpax · 1d ago
That's four posts about RSC in about as many days. Dan, please, you've got to pace yourself :sweat_smile:
danabramov · 1d ago
I kind of alternate between not being able to write and writing too fast so I try to catch the wave when it happens.
worthless-trash · 1d ago
Still dont know what RSC is from this page. As a lisp developer and not a javascript developer, I don't understand how onclick ends up with '/js/chunk123.js#onClick'
Maybe this is more meaningful for javascript developers. It makes little sense to me.
danabramov · 1d ago
When a compiler sees an import to a module with “use client”, it substitutes it with this reference. So the server code only sees the reference. Whereas the compiler also takes this as an instruction to bundle the code from that entry point. (Which ensures this reference actually corresponds to a file that will exist.)
Does this make sense? Like I said, I might be stretching the analogy, but it’s a bit like quoting except at the module system level (and in practice mostly happening at the build time).
I've edited the post to clarify this a bit.
worthless-trash · 1d ago
Thanks, that makes more sense.
jjraden · 1d ago
I'm guessing they mean React Server Components, but yeah, it annoyed me too that not only do they not define the acronym, but it appears only once on the page -- the title -- so that it's harder to infer it from context.
danabramov · 1d ago
Great callout, thanks! Edited. I meant the article more as "if you're already curious about the RSC model and have some LISP background" rather than an introduction to what RSC is, but hopefully spelling it out at least helps with that context.
owebmaster · 1d ago
There is a weird push/rebranding of React to actually run in the server, like Ruby on Rails or Django.
> It makes little sense to me.
You are not alone and I've been coding JS for the past 20 years.
Well, it makes little technical sense to me but it is not difficult to find where it might makes more sense.
revskill · 1d ago
Maybe, if you dropped React from RSC, you got only Server component, it means something more generical for you.
Now is it just html ? Yup, Html returning from server is a server component, executed by browser with DOM API (for script tag).
So if you understand Html and JS, you should understand RSC right ?
THe point here is, your html doesn't get rendered on server, your <script> tag doesn't get executed on server.
The server returns a program (code is data) to browser to render the document and execute script.
The real trick, is the server understands the html syntax (using string literal), so you got the illusion of isomorphism between 2 computers.
The server acts as "program generator", the client acts as "program executor".
Ok, it's just one piece of the whole.
The hard trick, is how to keep state preserved between re-rendering.
fn-mote · 1d ago
This post is almost vacuous. It explains quoting and then goes on to say:
> I don’t understand LISP well enough to understand [...]
Readers would be better off spending their time on a post with content.
For example, Racket has a webserver that uses continuations. Whether or not that's something you are interested in, at least it has intellectual content.
Would you say I mischaracterise LISP, or the analogy between quoting and sending modules doesn’t apply?
As I say in the article, I’m not familiar enough with LISP to understand how Electric works, but I’m a bit confused why you say there’s no content. I'm making a connection between the paradigms; if you find it vacuous, I think it would help to focus the criticism on the connection itself (why doesn't it hold?) rather than on me admitting the gaps in my knowledge.
I appreciate the link you’ve shared about Racket. From what I see, their continuations seem server-only, i.e. there’s no way to express client-side code in Racket (beyond HTML). What I’m interested is a more mixed approach where LISP orchestrates both server and client code, which would be a closer analogy to RSC.
kaoD · 1d ago
As someone that knows both Lisp and RSC, I don't think this is a great analogy since it misses nuances and intention in both sides of the equation.
The crux of Lisp's code-is-data-is-code is that you can manipulate S-expressions since they're a very simple data structure (think metaprogramming). I know you touched upon this in the article but acknowledging it doesn't make it less central to the issue.
I don't see the parallels except a very superficial similarity due to code being "serialized" (for lack of a better term, since that's not even what Lisp does) but that's just (1) a technical detail that glosses over the actual intention/capabilities and (2) not even true if we go down to the technicals.
But that might just be my personal priors, so take it with a grain of salt.
danabramov · 1d ago
To me, the common thing is having a first-class way to deal with something that's poised to execute later. RSC's way to do it is opaque, whereas quoting isn't opaque. In that sense, quoting is more powerful — which is why it can express both RSC and more mixed paradigms like Electric. But I think it's a meaningful connection because it's both about intent and capabilities. There aren't a lot of programming paradigms that enable cross-runtime composition and orchestration.
judofyr · 1d ago
From the article:
> It marks a piece of code to be treated as data (to be sent to the client).
> This means that whoever imports onClick from the backend code won’t get an actual onClick function—instead, they’ll get '/js/chunk123.js#onClick' or something like that identifying how to load this module. It gives you code-as-data. Eventually this code will make it to the client (as a <script>) and be evaluated there.
The point of quoting in Lisp is that you get the code actually as data: You can introspect it ("how many string literals are there in here"), rewrite it ("unroll every loop once"), serialize it, store it in a database. And more importantly: The code is structured in the same way as any data in a regular program (lists). It's not hard for the developer to do any of these things.
If I get back '/js/chunk123.js#onClick' I simply have a reference, which I can use to invoke it remotely. The code appears to still be sent as bundled JavaScript, evaluated as usual, and then linked together with the reference. There's a small connection to code-as-data in the sense that you need to be able serialize code in order to share it between a server/client, but other than that I don't really see much of a connection.
danabramov · 1d ago
Sure, and the article does acknowledge that directly:
>Of course, this is a lot less powerful than quoting because the evaluation strategies are being prescribed by React, and there’s no kind of metaprogramming like transforming the code itself. So maybe it’s still a stretch.
To me, the connection is that I'm able to treat a reference to serialized code as a first-class primitive that can be passed around the server code (and composed via component tag composition), but indeed it's not full-on metaprogramming.
However, I don't think this actually allows writing client-side logic in LISP too (beyond HTML that submits forms)? The point of RSC is to have the programming model actually span both sides. That's why I brought up Electric in the end, which does do that.
It's funny, as I could probably credit Dan with the reason I mostly spend time with Clojure and ClojureScript today. I think ClojureScript/Reagent/Om was mentioned really quickly when he did the "Hot Reloading / Time Traveling" talk back in 2014 sometime, which eventually led me to find Clojure which basically was made for making those things easy for the entire stack, not just frontend.
So thanks Dan for leading me to greener pastures, but a shame you still haven't taken the time to look into any lisp! Reagent+ClojureScript should be (relatively) familiar to you, as long as you get over the parenthesis-avoidance stage most of us go through :)
Common Lisp doesn't have as many opinions about your code, includes several nice features that Clojure skipped, and isn't chained to the JVM.
That's true for sure, and I'm sorry if my comment gave that impression, I'm not trying to say that Clojure is the only lisp, or even the best lisp! Just the one that fit me and my problems the best.
> and isn't chained to the JVM.
Neither is Clojure (the language), as it's available with JavaScript as a host (ClojureScript), LLVM (Jank) or even the Erlang VM (Clojerl). I'm sure there are more out there too, but the Clojure-JVM runtime isn't the only one available.
With that said, lots of people say Common Lisp is another good lisp, and been deployed in production for many decades, so I'm sure it's another great choice if anyone wanna get deeper into lisps. I personally haven't taken the time (yet!) to get to know it on any deeper level, so would be weird to recommend it before another lisp I know much better.
Personally, I think it does a few things better than Common Lisp and many Clojurists came from Common Lisp.
To paraphrase the late, great President John F Kennedy, "We choose to use emacs not because it is easy but because it is hard. Because that goal will serve to organize and measure the best of our energies and skills because that challenge is one we are willing to accept, one we are unwilling to postpone, and one we intend to win!"
If it used a Scheme implementation like in Halo:CE, then people would have justifiably hated it. If it used something more like MIT-Scheme, people might've been okay with it. But I suspect it would get the same hate that JS gets, since there is a lot of low-quality JS code floating around -- even though JS itself isn't remotely that bad -- and you would instead have a lot of low-quality Scheme code floating around. Damned if you do, damned if you don't.
FWIW, it is feasible to put Scheme/Lisp in a browser today, and it might even be fun. Take a browser that lacks JS (e.g. Dillo, w3m); figure out how to add Firefox's or Chromium's approach to isolating each Javascript instance; and embed a Scheme or Common Lisp implementation (e.g. Chez Scheme [1] or ECL [2]).
You will need to decide what Scheme/Lisp functions/macros to include/exclude. It may seem obvious to exclude file operations, but they did that with JS and now we have IndexedDB; a restricted, virtual file system might be fun to play with. Multithreading might seem like a great thing to include, until you start trying to implement secure multithreading. I would start with whatever cl-isolated [3] allows and expand/contract from there.
And before anyone asks, "would this actually be worth implementing in 2025?", the answer is decidely "yes". You could build powerful desktop applications without the full weight of Electron. You could develop local-network webapps for you and/or your company. But I think it would be a bad idea to deploy this on the open internet without first spending a lot of time securing the browser overall.
Another option is resurrecting Closure [4], which is written entirely in Common Lisp. In that, you could go on a wild tangent and support multiple scripting languages (e.g. Common Lisp via cl-isolated, cl-forth [5], cl-javascript [6], cl-python [7], scheme88 [8], and even Coalton [9]).
[1] <https://old.reddit.com/r/scheme/comments/a3oogf/questions_on...>
[2] With ECL, you could use cl-isolated in addition to OS-level containerization, to achieve more defense-in-depth. Or maybe port cl-isolated to Chez Scheme.
[3] <https://github.com/kanru/cl-isolated/>
[4] <http://closure.common-lisp.dev>
[5] <https://github.com/gmpalter/cl-forth>
[6] <https://marijnhaverbeke.nl/cl-javascript/>
[7] <https://clpython.common-lisp.dev/>
[8] <http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/s...>
[9] <https://github.com/coalton-lang/coalton>
I'm currently working on a project in Clojurescript, and I'm aware of some of the other options for running Lisp in a browser.
Is it really worth the headache and extra complexity?
Caveat: I've used Vue more than any other FE library/framework, but for the last 3 years I worked exclusively with React (via Next—app router). The company I worked (I left in Jan) for jumped on this RSC train as soon as it was released and boy,oh boy was it a mess! We ofteb got direct support from Vercel when our shit will break or not work as expected...
To say the app was slow and behaved unexpected would be an understatement.
Eventually, they had to rewrite everything back as a SPA.
I'm posting because I find the technology interesting. I don't have a goal of convincing you to use or adopt it. I sometimes write about specific aspects that I find appealing but YMMV.
I also hope you understand I wrote this based on my experience with it. ♥
So just like it happens in some many cases in our fashion driven industry, we get dragged into using tools we don't agree with, or be busy with yak shaving adding support for other tooling.
Server rendering is enough for the 80% use case. Browsers are optimized for it. Sprinkle interactivity without the impedance mismatch of jQuery and you're in heaven. No more overengineered state syncing between client and server. Just. Fetch. HTML.
Currently frameworks are trying to shoehorn it into the 2018 React mindset but that's not what I think is needed for them to succeed.
I posit that any composable version of sprinkles or the “island architecture” will closely resemble RSC.
Only a small fraction of apps will ever use the full power of the RSC architecture. However, the React team doesn’t build apps, they build primitives for building apps. And good primitives are composable.
What they did wrong tho was to morph React into this mess. RSC should be React Server and live along React DOM and React Native, something almost unrelated to the previous concept of React. But we got this an entangled mess.
Is that your axiom or do you have any justification? I just don't agree with it.
Why should the server know about a datepicker's internal details?
There's some case where local state is more important (figma, google maps, chat app) and the backend is expected to act as a data source with a domain-specific API. Any mixture between the two and you will make the separation between the two domain (server concerns and client concerns) at the wrong place, making the design more complex (however well you hide it behind the curtains).
Which is exactly why the client state should be transient non-application state like datepickers, dropdowns, text boxes, etc. and it does not belong in the server (essentially what jQuery was used for back in the day, interactive sprinkles). And the other way around.
Perhaps you agree with me but there was something lost in translation?
RSC does a weird split where the engine is the same on both ends instead of a clear separation layer where one does not need to know about each other. I much prefer HTMX approach (samey old backend where you mostly take care of everything in the frontend) and Laravel Livewire approach (where you take care of everything backend side, with optional client side scripting).
No need to reinvent the world to fix a single problem.
I'm not sure. It felt like we were moving towards dumb backends that sync automatically towards frontends that would contain most logic. Things like https://localfirstweb.dev/ or https://electric-sql.com/ felt like the future
Writing more server code (as quoting/react-server-components are suggesting) will increase the surface area where errors can occur. Limiting that to either just the server/client feels like a much saner approach
I think the same argument applies to RSC. For many use cases, it doesn't make sense. Many organizations and projects do not need SEO or server code specifically for their FE. If the organization has committed to an API service in order to support a range of clients then RSC/react server framework is "pure overhead."
As someone who has been building with React for a decade, RSC was the moment where I felt the complexity vastly outweighed the benefit. I'm in a position where I can argue that SPAs are dramatically simpler to implement compared to RSC/nextjs, which I think would be surprising to outsiders who bemoan SPAs as complex.
I find the "preload then rehydrate" data synchronization model simpler to understand and can turn even the slowest APIs into an app that feels instant: https://starfx.bower.sh/learn#data-strategy-preload-then-ref...
I think that's a slightly different kind of message than "servers are unnecessary, peer-to-peer is the future". You can keep servers dumb, but some kinds of product features demand the servers to do the job. And then if you want to squeeze the most out of the server as it relates to your client app, RSC is one way to look at it.
I feel like the design space of making the server as dumb as possible is not sufficiently explored yet. I’m imagining PWAs that work offline by default, hosted on static hosting, talking to CORS-unlocked PKCE-authenticated APIs, storing their state as dumb files in APIs like dropbox, and doing all of the cross-client p2p syncing and merging client-side inside of a service worker.
It wouldn’t work for all categories of software, but so much productivity software ultimately reduces to a per-user file paradigm instead of a central database (outliners, notes, task managers, image editors, …) that I think a lot of complex web apps could be built this way. They wouldn’t work well on low end android phones, but then most of the products from those categories already don’t work well there, when half their logic is still on the server.
And yes, I know, Apple does not play nice with PWAs, but I still think there’s something there that I wish more people would explore.
Maybe this is more meaningful for javascript developers. It makes little sense to me.
Does this make sense? Like I said, I might be stretching the analogy, but it’s a bit like quoting except at the module system level (and in practice mostly happening at the build time).
I've edited the post to clarify this a bit.
> It makes little sense to me.
You are not alone and I've been coding JS for the past 20 years.
Well, it makes little technical sense to me but it is not difficult to find where it might makes more sense.
Now is it just html ? Yup, Html returning from server is a server component, executed by browser with DOM API (for script tag).
So if you understand Html and JS, you should understand RSC right ?
THe point here is, your html doesn't get rendered on server, your <script> tag doesn't get executed on server. The server returns a program (code is data) to browser to render the document and execute script.
The real trick, is the server understands the html syntax (using string literal), so you got the illusion of isomorphism between 2 computers.
The server acts as "program generator", the client acts as "program executor".
Ok, it's just one piece of the whole.
The hard trick, is how to keep state preserved between re-rendering.
> I don’t understand LISP well enough to understand [...]
Readers would be better off spending their time on a post with content.
For example, Racket has a webserver that uses continuations. Whether or not that's something you are interested in, at least it has intellectual content.
https://docs.racket-lang.org/continue/index.html
As I say in the article, I’m not familiar enough with LISP to understand how Electric works, but I’m a bit confused why you say there’s no content. I'm making a connection between the paradigms; if you find it vacuous, I think it would help to focus the criticism on the connection itself (why doesn't it hold?) rather than on me admitting the gaps in my knowledge.
I appreciate the link you’ve shared about Racket. From what I see, their continuations seem server-only, i.e. there’s no way to express client-side code in Racket (beyond HTML). What I’m interested is a more mixed approach where LISP orchestrates both server and client code, which would be a closer analogy to RSC.
The crux of Lisp's code-is-data-is-code is that you can manipulate S-expressions since they're a very simple data structure (think metaprogramming). I know you touched upon this in the article but acknowledging it doesn't make it less central to the issue.
I don't see the parallels except a very superficial similarity due to code being "serialized" (for lack of a better term, since that's not even what Lisp does) but that's just (1) a technical detail that glosses over the actual intention/capabilities and (2) not even true if we go down to the technicals.
But that might just be my personal priors, so take it with a grain of salt.
> It marks a piece of code to be treated as data (to be sent to the client).
> This means that whoever imports onClick from the backend code won’t get an actual onClick function—instead, they’ll get '/js/chunk123.js#onClick' or something like that identifying how to load this module. It gives you code-as-data. Eventually this code will make it to the client (as a <script>) and be evaluated there.
The point of quoting in Lisp is that you get the code actually as data: You can introspect it ("how many string literals are there in here"), rewrite it ("unroll every loop once"), serialize it, store it in a database. And more importantly: The code is structured in the same way as any data in a regular program (lists). It's not hard for the developer to do any of these things.
If I get back '/js/chunk123.js#onClick' I simply have a reference, which I can use to invoke it remotely. The code appears to still be sent as bundled JavaScript, evaluated as usual, and then linked together with the reference. There's a small connection to code-as-data in the sense that you need to be able serialize code in order to share it between a server/client, but other than that I don't really see much of a connection.
>Of course, this is a lot less powerful than quoting because the evaluation strategies are being prescribed by React, and there’s no kind of metaprogramming like transforming the code itself. So maybe it’s still a stretch.
To me, the connection is that I'm able to treat a reference to serialized code as a first-class primitive that can be passed around the server code (and composed via component tag composition), but indeed it's not full-on metaprogramming.
This is indeed close in some ways — make-js-action roughly corresponds to "use server" in RSC (https://overreacted.io/what-does-use-client-do/#use-server).
However, I don't think this actually allows writing client-side logic in LISP too (beyond HTML that submits forms)? The point of RSC is to have the programming model actually span both sides. That's why I brought up Electric in the end, which does do that.