JS Party – Episode #311

React Server Components 🧐

with Dan Abramov

All Episodes

The week Amal & guest co-host Eric Clemmons talk to Dan Abramov all about React Server Components. We learn about why they were created, what problems they solve & how they work to improve application performance. We also dive into the rollout and current support status, the origin story, the community response & walk through the 10+ years of React history which have forever shifted the world of web development.

Featuring

Sponsors

VercelZero configuration for over 35 frameworks Vercel is the Frontend Cloud makes it easy for any team to deploy their apps. Today, you can get a 14-day free trial of Vercel Pro, or get a customized Enterprise demo from their team. Visit vercel.com/changelogpod to get started.

PowerSyncDon’t build your own sync layer! PowerSync enables an offline-first architecture to make your application real-time and reactive. PowerSync is framework agnostic with open source client SDKs and plugs into your existing database, backend, and application to give you an offline-first/local-first architecture without having to build your own sync layer.

Fly.ioThe home of Changelog.com — Deploy your apps and databases close to your users. In minutes you can run your Ruby, Go, Node, Deno, Python, or Elixir app (and databases!) all over the world. No ops required. Learn more at fly.io/changelog and check out the speedrun in their docs.

Notes & Links

📝 Edit Notes

Chapters

1 00:00 It's (Dance Party!) time, y'all 00:39
2 00:39 Sponsor: Vercel 02:43
3 03:22 Hello, JS Party listeners 01:36
4 04:58 Welcoming Dan Abramov 01:35
5 06:33 Welcoming Eric Clemmons 01:21
6 07:54 click-to-component 01:08
7 09:03 React love stories 06:39
8 15:42 JavaScript fatigue 03:32
9 19:14 The evolution of React 21:43
10 40:57 The uncanny valley 07:01
11 47:58 Sponsor: PowerSync 03:32
12 51:30 First-class data fetching 15:16
13 1:06:46 Client-first FUD? 05:54
14 1:12:41 RSC in the networking tab 03:58
15 1:16:38 The bundler question 05:10
16 1:21:49 No server required? 16:16
17 1:38:04 On linting 01:58
18 1:40:02 Next & integrations 13:42
19 1:53:44 So... the name 03:47
20 1:57:31 The rollout: differently? 03:24
21 2:00:55 Dan's one web wish 03:10
22 2:04:05 Wrapping up 02:09
23 2:06:14 Next up on the pod (Dance Party!) 00:55

Transcript

📝 Edit Transcript

Changelog

Play the audio to listen along while you enjoy the transcript. 🎧

Hello, JS Party listeners. Welcome to yet another week with us. We’re very excited about today’s show and today’s guests. We’re gonna be talking about React Server Components, and deconstructing them with Dan Abramov, who’s here to help us bust some myths, set some truths, do some deep dives, set some facts… I’ve already been fact-checked seven times, just in preparation for this show. Dan’s already set the record straight, so I’m excited to continue to be fact-checked. With us to ride along with us for this ride today is Eric Clemmons, my friend who I invited to essentially play [unintelligible 00:04:18.17] role, because I think I’ve been outside of this React community for a little bit now, and I’m coming at this from the skeptic’s perspective… And Eric is very deep within, and he’s a [unintelligible 00:04:29.22] and he’s a lover of all the things, and he’s been playing around with RCs, and he loves them, and so I’m really excited to have his voice on the show. And then of course you have Dan, who’s been part of the core team for many years, and generally been educating the community for many years around best practices, and how to use React, and all of that jazz. So I’m super-excited about today’s discussion. So with that said, let’s get started with introductions. So welcome, Dan. Can you tell us a little bit about yourself? …even though I feel like you don’t really need an introduction.

Yeah. First, thank you so much for inviting me. I’m super-happy to be here. So I started using React in 2014, I think, and after that I joined the React team in 2015, and I’ve been on the React team for about eight years, I think. I’m currently on a break, because - so I joined BlueSky, which is a company that uses React, and React Native, so I’m actually learning React Native, and learning how to use it… And I’m really in the product development mindset as a user of React now… So I haven’t actually been very involved with the team, and I speak in personal capacity on this show. So yeah…

Dan, it feels like the React core team is a little bit like Hotel California, where you can never quite leave, because I know you’re not officially part of it, but… Based on the internet, you would never know; you would never know. Because you’re talking about it, and you’re in all the things.

[00:05:58.07] I feel like it’s actually the other way around, because officially I am still on the team, but actually I haven’t showed up to meetings for a while, just because I’m too overloaded trying to learn React Native… So I do want to get back to it, so I’m on a bit of a sabbatical, I guess.

So you’re talking about React Native… I want to know, when is BlueSky going to have a web client?

It does. Yeah. So there is a bsky.app. I think that’s – I might be wrong, but I think that’s the current URL. We have three different domains… I keep forgetting which one is which.

Okay, I’ll have to check out the web client. That’s great. And so Eric, again, welcome back to the show. Can you give our listeners a little bit of – I mean, besides you’re a mega DX nerd, tell us a little bit about yourself.

Yeah. Thanks for having me, of course. But it’s interesting, I’ve been in the web space for such a long time. People are like touting their tenure in web. But what I think is really interesting is just the evolution that’s continually happening… And one of which was whenever React dropped. I think the 0.12 days. The company I was at, we were focused on just building like web forms… And as long as we got the job done, they didn’t really care how we built things. So we got to cut ourselves on the bleeding edge a little bit… But the thing was React really was a hero from the very beginning, going from an Angular app and PHP apps, we went to server-side React back in the day. Probably a little too soon, and had to figure out async data fetching, and serializing data and stuff… But the result of it was millions of dollars of actual conversions that happened as a result of faster rendering, response times… Progressive enhancement basically was what we shot for there. And so React was the thing that made us successful for I think six years of just [unintelligible 00:07:48.05] to build off of. So I wouldn’t be here if it weren’t for React, actually, I’d say.

Yeah. And you have some pretty popular libraries too, one of them being Click to Component, which I really love, and I feel like more people need to know about that and use it. But it’s a component that – like, do you want to tell people about it?

Yeah, I mean, everything’s born out of a DX need. And I wish I could just be funded full-time to take all the paper cuts that developers deal with, and make them all 10x engineers… But yeah, the long and short of it is that most of the time when you’re doing web development, you see what’s on the page, you say that’s either right or that’s not right, and you just need to go to the source code, and go into the dev tools. It won’t get you straight to the source code, but Click to Component is a wrapper. There’s a Chrome extension of that. I think it’s actually surpassed it in terms of functionality and multi-framework support. I don’t have a name for it offhand, but I think it’s probably the way to go for individuals who just want to look at the page, go straight to the source, fix it, and have a faster feedback loop. But that’s actually the long and short of it, is being able to focus on what you’re trying to do, and get all of the annoying friction and steps out of the way in between you and just getting your job done. And actually, I think RSCs play into that narrative pretty well.

That’s awesome, and excited to dig it in. So before we dig into RSCs, I want to do a couple things. One, I want to hear from both of you on what is your React love story… Because the three of us didn’t found it, so in theory, we saw it and we were like “Ooh…!” So what’s your React love story? And then I want to get into the evolution of React, and that will take us into RSCs and where we are today. I’ll start first with my React love story. So for me, I think I came into React from the Angular 1x world, and Backbone, and CanJS, and Knockout… So many different things. jQuery… It’s a whole smorgasbord of things, including Rails, PHP… A lot of things. And I think for me what just clicked was that it just made sense, looking at a React component and the way things were structured. The fact that everything was just JavaScript for me was the big a-ha, because I didn’t have to learn any additional syntax. If I wanted to loop, or map, or do whatever, it was just JavaScript. Sure, there was a couple of things you had to learn around what is the syntax around JSX, but for the most part, everything just felt very intuitive.

[00:10:15.14] And I think for me, starting to become a lead at that point, just seeing how much of an accelerator it was for teams, quickly creating components, being able to compose them easily, being able to organize their code in a better way… You were able to go from zero to hero very quickly, and I think that was really exciting.

Of course, it came along with some pretty big shifts around, like you had to use a compiler for the first time in the JavaScript world, and you were getting things from Npm… And that was new. But for the most part, huge accelerator, and I was a huge fan of React. I think for me where I shifted into a skeptic was specifically around when I started to see frameworks like Preact, come along, and have a very similar API with a lower bundle size, and better performance… And I was like “You know what? I would really like more of a focus on performance.”

The other skeptic – my skepticism grew with how Suspense, and concurrency, and some of the other shifts in the API, where I was like “You know what, I really want to just focus more on performance. Let’s just fix that problem.” And then I moved into different spaces, and that’s just where I dropped off. But for the most part that, that’s my love story with React. And I think it obviously really shifted the ecosystem forward as well, in terms of design. So Dan and Eric, eager to hear from you both.

I think it’s actually interesting you mentioned that you were interested in performance, but then the things that shifted your attention were – these are features for performance. So there is an interesting irony there…

It is ironic. I think it was just that the API – it was around the same time that… I know Suspense was there to improve perf to some degree, but the point is, the API around hooks, I think the design also really bothered me specifically. I felt that it just wasn’t intuitive. It it just – everything in React was intuitive until hooks came along, for me. This is my personal opinion. I think that’s where for me the seed of skepticism was planted, and it has just never fully gone away. But I’m hopeful – again, I’m here to hopefully change my opinion on things… So I’m coming to this conversation with an open mind. So… Back to you.

Sure. Yeah, so for me, I think the first time I looked at React, I thought “That just looks silly.” But I was pretty new to web development at that time. Before that I was doing mostly desktop development, with C#, .NET, and a little bit of mobile with iOS and also C#, using what’s now called Xamarin. I don’t know if that’s a thing anymore, but… That’s what I was using. And then we started using Angular 1.x for a little bit, built some UIs with it… And at some point, React came out; I dismissed that originally, I didn’t get it. And then my colleague – a few months later, my colleague sent the link to React again, and he goes “No, check it out. There is something to this.”

At the time I was working on an app where you could post different multimedia posts with images, galleries, text, and a bunch of stuff, and I was at the time working on the Like button. So I needed to add a Like button, you can press Like, it shows you liked this, or you and Andrew liked this, or you and three people liked this. So it has to show different things, depending on what the data is, and then when you press it, it can push it over into one of these different states.

[00:14:09.08] At the time we were using Backbone, and you had to write your initial template for the initial data, but then you had to listen to events, “Did I press the button?”, and then change the template dynamically to the final state… And then with React, the first time I tried it, I realized “Oh, I can just write an if statement.’ So if nobody liked this, then returned this; if one person liked this, return this. And React handles the transitions between the states. So I can just describe the user interface as a function of state, or as a frame in a movie, and there is only the current frame; you never think about time.

So this was my first React component, just a Like button. And then we started trying it in a few more replaces, and it just ate our app from inside out, because it started somewhere deep, and then we gradually started using more and more React as we climbed higher. And even though – I think that was before, you know, people were complaining about JavaScript fatigue, and all that stuff… We were excited, because everything used to be so bad. It was just very hard to build dynamic UIs, and we were rewriting our product in React at the same time as shipping features, and actually, we were faster while doing the rewrite, just because React enabled us to make everything so dynamic. So that’s how – I think that that was that moment for me.

You know what you’re doing mentioning JavaScript fatigue there, Dan… I see what you did.

That was like attacking Eric, yeah. Eric had a famous viral blog post from back in the day titled exactly that.

Yeah, that was such an interesting thing, because I think that that blog post actually got us talking a little more one on one… Because that was right before the Create React App abstractions, and those days; babel/preset-env wasn’t a thing… So that did strike a chord with the React community. But I don’t think actually because of React. I think it was because of everything else around React, in retrospect.

But it’s so funny, we have such interesting and similar love stories. We got into it around the same time, on the ground floor… And I think that’s a bit of our honeymoon period, where a lot of people who’ve gotten in there early, they see React today and that’s not the React that they fell in love with 10 years ago, it seems. They comfortable with –

That’s me.

Yeah. It was successful, it got the job done, but it’s not how you do React anymore. It’s like, you’ve changed, but I haven’t. But yeah, it was an incremental thing for us, too. We had a PHP-based business. The page response times were around 800 milliseconds or something like that… And we had the issue of just complex form logic, and we wanted to make sure that when we submit forms and validate data, that the logic in the PHP backend was the same as the frontend that we were trying to improve for good experience… And so like “If only we could use JavaScript everywhere.” And once we did that, the response times went to 200 milliseconds. And that was our first attempt at using React; it had already gotten that much better. And in eCommerce, you improve response times and conversions go up. And then we got it down to like 40 milliseconds, and the business was just like “Whatever you’re doing, step on the gas. Keep it up.” And so we just went headstrong into everything else around React, the whole JavaScript ecosystem.

We got deep into WebPack 2 at the time, released. We got async bundles and code splitting to improve performance even more… And then looking outwards. Because of React’s success, it made us look at other things, like “Well, what else can we do that this community is doing?” It led us do continuous deployment. And we were deploying dozens of times a day for a business that was deploying once a week, or once every two weeks and had a multi-hour deployment process.

[00:18:09.00] So I would say React was like that first hit of the JavaScript drug that got us successful, gave us that high, and then we kept going with everything else in the ecosystem. And we had no idea – you know, people talk about a new framework every day, but there’s a new solution so often that’s solving some problem unique to maybe your case, but some that don’t apply to you, and you get to just have a buffet of stuff that’s potentially going to make your business better. And we were able to ride that wave for years, until I left the business, like six years or something later, after the initial adoption.

So yeah, I’m doing Python today… Dan, you were talking about learning React Native… I’ve had to learn Python. Thank you, ChatGPT and Copilot for teaching me Python syntax… But it makes me miss the velocity I had of being able to have end to end JavaScript, React, and that locality of behavior.

Yeah. So well said, Eric… And yeah, this is a pretty good segue into the evolution of React, because you mentioned that person from 10 years ago that was using React; maybe coming into it today, it would be like “This feels very different.” I think I started at 0.12, 0.13. That’s when we started using React in production. And we had a very innovative leader on the engineering side, who was very bullish on good tech, and wasn’t afraid of being on the bleeding edge… And even though that was very early, they were totally willing to go all-in on React. So Dan, can you talk us through React from 10 years ago to where we are today, going from these components that were often used on the client, specifically… They weren’t always SPAs, but for the most part, kind of going into the server-side rendered revolution, fueled by frameworks like Next.js, and then to where we are today, ushering in this data fetching as a first class world, with React Server Components.

Yeah, let me try to recap the… So we’re talking now about paradigms of where we run the code, right? So not so much the syntax, but more just how we use computing resources. And one way I like to think about it this – in general in app development, but specifically in web development… Like, in web development you always have to think about at least two computers. So there’s the device that the user has, so it could be their phone, or it could be a desktop device… They’re probably using the browser to open your app… And then of course, there has to be some other computer that actually sends the information to the user, right? So there has to be some kind of a server, that either sends HTML, or JavaScript, or both, or some JSON… And so the question is just like “How do we use the resources of those?” Of course, there could be another computer earlier that maybe does the build, or when you deploy – like, somehow the code has to get from the developer’s machine to that server. So there’s also some kind of a step of deployment. So the question is how do we split the resources between these different computers, and what do we actually make them do?

[00:21:36.07] So at the time when we just started using React – I mean, there were already different paradigms of how to split these resources. One very popular paradigm was traditional server rendering, unrelated – when I say server rendering, I mean like PHP, or Rails, where you mostly write your UI logic as HTML-ish templates, which you have some control flow; you have things lik loops, conditions, you have some kind of includes maybe, so you can put one template into another template… And that is happening completely on the server side, so you’re able to directly access any resources that are on the server. For example, you can read from the database, you can read from the file system… Of course, you can also build a bunch of services and just talk to them by HTTP on your servers, so that is something you can always do, but you’re also not forced to do that, if it doesn’t make sense for some task.

So that was the paradigm… But then, within this paradigm, it’s pretty hard to build very dynamic, very instantly-responsive user interfaces, because if your UI logic is completely on the server, then you have to talk to the server to get any kind of visual update. And for some cases it’s fine. In something like drag and drop interactions, or gestures, or just typing into an input and immediately – for example like filtering a list without going to the server, stuff like this, you can’t really express it in this paradigm very nicely. And then that is where we started the shifting of more work to the client, where maybe you’d have some jQuery plugins that enhance the HTML you return from your server templates… And that let you add some instant interactivity where you know that the screen can update without a network round trip.

You could already go extreme in either direction at that time, because you could have everything that’s server-rendered, with something like PHP, and maybe a few jQuery plugins to just enhance it in a few places… But there was also this approach of single-page apps was starting to gain traction, where you actually wouldn’t send any HTML at all, and instead, you would only send JavaScript, and then the JavaScript would be creating that initial HTML, and managing the DOM nodes completely on the client. And so the benefit of that paradigm is that you have the guarantee that you can always make an interaction instant. So you have this guarantee that you’re not going to get locked out of being able to show immediate feedback, because all the code is on the client, and so all the code that’s necessary to produce the UI is already available. But then the downside of that is, of course, you have to download a lot more code upfront. You don’t show anything to the user while the code is loading, so it’s kind of bad for performance. And it also complicates the mental model quite a bit, because now you’ve had to move all the routing to the client, you have to have some caching for any data… You have to think about state management, like “How long does this data live?”, in which case does it invalidate, when is it okay to throw away? So it’s painful in a different way. But when React came out, these were two popular paradigms… And so React was used in both ways.

For example at Facebook, React was used more in this jQuery scenario, where we’d initially use React. For example in the facebook.com web app, React was used only in the comments section of each post. So the entire page was server rendered with PHP, but the comments section was actually rendered with React, and React kind of took over, so that this particular piece can be instantly interactive. Whereas in the community, I think some people adopted React like that, whereas other people already have single-page apps with something like Backbone, or Angular, and so they already had all their code on the client, and so they started kind of replacing initially just small parts of it with React, but gradually… Because it’s not a server-based paradigm, you can go all the way up and replace it with React completely.

[00:25:59.20] So I think in 2015 or so React Router got fairly popular… That was I think the first major popular solution for routing fully on the client, without going to the server to decide what the route should show. Fully client-side paradigm. And especially when Create React App came out, it kind of solidified this as – because if everyone is running… Like, all the server solutions are very different, so you can’t really release any tool chain that addresses them all, because it has to be custom anyway. Whereas if you’re moving everything to the client, that’s easier to kind of agree on, that “Here’s the baseline of how these features could work.” And so Create React App made this approach even more popular, because it became easy to start with – you’d just run it and you’d get yourself an SPA.

I think you just answered a long question that I had, Dan, which is why when React was first released into the public - not necessarily internally - why wasn’t there a router? And I think it’s obviously because Facebook wasn’t using it that way. They were using it to supercharge parts of their web app, right? Essentially, that’s not how they were using it.

Yeah, yeah, absolutely. Yeah, that is part of the reason. Facebook generally doesn’t release something that they are not themselves using, and Create React App was an exception to that, because Create React App was not used at Facebook at all… But there was so much frustration in the community about, you know, we have these five different tools that need to talk to each other, and they’re very finicky to configure… And the idea with Create React App was like – it actually came out, like, we were supposed to write a documentation page about setting up React, and it was just embarrassing, because it was like “Set up these five different tools, and then make this tool talk to this –” It was very confusing, and it didn’t make sense that every time each of these tools update, everybody has to look for updated instructions. So we were like “Okay, let’s just make a thing that hides them behind an abstraction level.” The abstraction level kind of went up.

Yeah, and so that’s how SPAs with React became the norm, I think… But we already know there are at least two or three problems in this paradigm. One problem is that we don’t send any HTML on the initial load. And I think when you don’t know how to do it, or when there is no nice way to do it that’s maintainable, I could kind of see it or understand it. But we’ve figured out how to do it. We’ve figured out good ways to do it, that doesn’t require you to write your code two times.

For example with something like jQuery, if you have a jQuery combo box, or a dropdown or something, you can’t really produce HTML from it, because the whole paradigm of jQuery is you operate on the DOM nodes. So any UI logic is expressed as you take a DOM node, you change its attributes, and so on. So you can’t really extract what is the initial render, what is the initial version of this UI. You can’t run some jQuery code and figure that out on the server. But the thing that’s interesting about React was that because it’s a function of state, you could call that function with the initial state; you get a tree, and then you can turn that tree into HTML.

[00:29:43.26] And so we have this client-side app; it’s conceptually client-side, it’s written for the client. But we figured out that actually, we can run the client-side app on the server, once, per request, produce HTML from it, and then send the actual client-side program to the client, so that it can boot up on top of that HTML. And so that’s what’s usually called SSR in the React paradigm, it’s just this ability to generate an initial pre-rendered snapshot of the client-side app client tree, but on the server. So that’s why it’s called server-side rendering, but it’s really client rendering; pre-rendering the client on the server.

And there’s another variation of that – like, Next.js became one of the popular ways to… One of the first frameworks to do SSR in React, although - again the ability to do SSR is provided by React itself; it’s just React DOM/server, render the string. That was the initial API. And then Next.js was kind of like Create React App, but that was designed around this idea that actually we already know how to pre-render the client tree on the server, and we might as well do that.

And then the other innovation we had was a filesystem-based routing. So the idea was - well, in a traditional PHP app, if you go to pages/about, it has some script tags about that PHP, or whatever. It sends some script tags to the browser. So you have the ability to send different client code, depending on what page you’re on. And so in that sense, the SPA paradigm is a regression, because now we send the code for all possible pages, even though the user has actually requested a specific one. So that’s not really efficient. So the other thing that Next.js did from the beginning was that, unlike Create React App, where everything is sent as a single bundle, or you use bundle splitting, but you can only do this once the code has downloaded… In Next.js the components you used from the page would get sent in script tags from those pages, so code-splitting was built in.

I was gonna ask a question that I think you’ve somewhat answered… The whole SSR - remember that function, render to string, right? So ultimately, it wasn’t the most performant… And I’m curious, was Facebook using that internally? And if it was, then why wasn’t the performance more of a focus in subsequent releases, just kind of like getting that down?

Yeah, so I think there’s a misconception in general when people talk about React performance, because a lot of this comes from marketing – you know, JS frameworks benchmarks or something like this, that runs a tight loop with one component level, or three component levels… And that shows you the – it’s like looking at the microscope at one tiny part of what actually executes, whereas in any real app, most of the time is spent in executing the user’s code; the code that you write, your components. And so the problem with render to string - you’re absolutely right that there were performance issues with it, but I think there’s a misconception that maybe these performance issues are just because “React was slow. So let’s just make React faster.” That’s not really how it works, because it’s just a while loop. It doesn’t really do much. It’s like a while loop that calls your components, and concatenates them into a string. So there isn’t really much to optimize there.

The thing you could optimize is – well, it’s about how do you sequence different things that the app needs to do. So as an example, if you want your initial HTML to contain some data, there is a question of “When do you kick off these data fetches?” Do they happen during rendering somehow, or do they happen ahead of time? And typically, because in React there was no support for asynchronous components, there were no built-in asynchronous primitives, you always had to do this - if you wanted these data fetch results to be in the initial HTML, you had to do them ahead of time. So you had to do await, fetch, or whatever, and then render your tree… Which means you’re not really using the computing resources of the machine, because you could have started doing something, but you were waiting for all the data to be available before you started.

[00:34:30.19] So it’s a sequencing problem, and that is why – Facebook couldn’t use… Even as Facebook started adopting – so Facebook started rewriting their main app fully in React in 2017 maybe; I’m not sure. Or 2018, around that time. And because renderToString was synchronous, that was just a non-starter because for Facebook it’s just the fact that a page is composed of many different things. Some of the things are going to be slower than others, and we can’t wait for everything to be ready before we emit all the HTML. What we want to do is just trim it. So we want to start rendering the components, then if some of them are not ready, we want to send some kind of loading placeholders, or just hold the stream for a little bit… And then when they’re ready, we continue and we just emit more and more things in the stream.

So answering your question of why Reacted didn’t focus on that - React actually did focus exactly on this, but from this other perspective. So not from the perspective of trying to make React faster, because you just run into limitations of – there’s only so much you can do with a while loop. But from the perspective of “How do we schedule the code written by the users of React, so that we can stream as much as possible until we’re blocked on some data that we just can’t render something, because we’re awaiting, and then we emit some placeholders”, and so this is the Suspense API, where you can say “I want to send this shimmer, or a glimmer, or a loading state”, and then React will automatically send the rest later. So that was streaming server rendering; that’s something that React 18 came out with, and without that, Facebook could not have even moved to using React on the entire page.

So this is really interesting to hear, because – I mean, it kind of takes me back and triggers some nostalgia, but also, the data… I’m gonna use those numbers. So before PHP application, 800 milliseconds. React application, 200 milliseconds. And then finally, we landed around 40 milliseconds. That was a win. Could it be sub millisecond today? Yeah, probably… But at the time – so all the same data fetching existed. So React was just the implementation detail of how were we going to make… I think that UI as a function of state has done so much heavylifting in terms of selling React, and also composing components, and writing Markdown with event handlers and everything kind of like together… It just clicked. Versus the progressive enhancement days of jQuery, like you mentioned, where you’re primarily mutating DOM nodes, and you don’t even know what it’s even supposed to look like at a state 20 of 400.

So whenever we got to 200 milliseconds – the first open source library I wrote was called React Resolver, and it was using decorators at the time, which were experimental, and that I actually had to remove from some old code at my job, actually. We had legacy decorators still in the code, and it’s like “Ooops, gotta nix that.”

But anyway, it effectively just wrapped components with “Hey, fetch this API, and then you can keep rendering.” And that’s what got us to 200 milliseconds. We were rendering the full tree synchronously, whenever we hit basically that React Resolver decorator. It’s like “Okay, fetch the data. There’s gonna be waterfalling, but we’ll paralyze anything at the same time. And then we’re going to re-render the tree until we hit it again.” So it was very inefficient, but it was still four times faster than whenever we tried to do it with PHP, and render the templates and everything.

[00:38:10.13] Finally, we actually said “Well, hang on… Do we need to fetch all this data right here?” And we took out some of the server side rendering, and we ended up rendering just basically the initial shell, with a Suspense-like spinner, loader in the middle of the page, and then the rest of it we fetched on the client. And that’s where the server was spending 40 milliseconds. But in terms of the user experience, it felt faster, because now it was five times faster to actually see the code on your screen.

So whenever I see React today, it feels like all of the Wild West paradigms and hacks that I had to put together to get the experience I want are really taking all of the data needs, that never went away, but I was just kind of moving on from the right, to the left, and then threading on through different parts of the UIs to yield the best UX… It just seems that over time, with the introduction of Suspense, that it’s like okay, now there’s first class primitives for me to use to get the behavior that I had to hack around myself for. Would you say that’s kind of accurate?

React today compared to the React ten years ago is to me honing in on web problems. The data fetching was always kind of there. The latency across network boundaries and API calls was always there. Talking to the database was always there. Caching was always there. And where do you cache, and how do you invalidate? That stuff was always there.

What I see for React in the most recent RFC discourse is we have 10 years of learning, of people building, going from counter examples, which I personally don’t find very helpful for illustrating the value of frameworks anymore… So I wish button counters disappeared. Unless it’s PartyKit showing a demo. That’s totally fine.

[laughs]

The PartyKit demos with server-side, or Socket RSC was pretty cool. But it just seems like React was able to say “We can better serve this need with these better abstractions, or paradigms, or whatever.” And also, it went from “Oh, React doesn’t have a router. You bring your own router”, that sort of thing. As part of that learning exercise and building more and more ambitious applications on React, it seems that it became necessary for React to say “Well, we’ve got to work with bundler integration, because you have to bundle an app today.” If you did a single page app - yeah, it made your React code base integrated, everything was collocated together, it was all component-driven, it was instant from the UI… But it also ended up yielding terrible dev experiences too, and terrible user experiences, because it started shipping 10 megabyte bundles as well. So I see the pendulum moving back and forth, and as a result, new abstractions just had to arise as part of that learning.

Yeah. So you jumped a little bit ahead to Server Components… Which - we do have to get to that stuff at some point, of course…

Oh yeah, yeah.

We do. Actually, hold on, Dan. Before we respond to that, I did want to ask about the uncanny valley… The problem where we send over this serialized HTML that looks intractable, but there’s still JavaScript that needs to be parsed before that page is interactable… And so that was also another issue that became a thing with a lot of server-side-rendered applications. This wasn’t specifically just a React problem. And so I’m just curious also, if you could shed some light there and how RSC potentially helps that.

Yeah. So I do want to get to RSCs just a little bit later, because this is more like a kind of history of… I like Eric’s framing of “We’ve learned for 10 years, and we actually took a step back.” And I think this is the point that’s maybe not coming across, is that RFCs are kind of taking a step back from everything we’ve seen for the past 20 years, and then rethinking it, like “How do we apply all these lessons while having a component model?”

[00:42:16.11] So far, it feels like we keep stacking up more and more complicated things to address issues, but I do feel like RSCs are also a step back in like “Okay, how do we make it simple again?” But before we get to that - so answering your specific question about… Like, you’re absolutely right, there is this problem of, okay, if we do have a lot of JavaScript to send, and we send HTML, but then it looks like there’s a button, you click it, nothing happens… So this is something that was also a problem for facebook.com… And we had a pretty long period of rethinking SSR, and this process of sending a pre-rendered app, and then setting the code for the app, and then having the code to the app kind of attached to that HTML. So this is a process that we changed how it works in React, and the key innovation there was also inspired by our old-school PHP setup.

So there’s this thing called BigPipe, which is a technology Facebook used from 2010 or so. I think it was described in some blog post. It’s this idea of - instead of sending all of the code at once, and even all HTML at once, you kind of send it in chunks… Because in HTML, traditionally – even if you stream it, so even if you send it as it becomes available, streaming in HTML is depth-first. So you kind of have to stream each child after – you kind of have to drill down into the tree as you’re sending it. But then if you have this problem where for example maybe you serve a profile, and you have the profile feed, you have the About section, you have the Photos section, you have the Events section, or something like this… And let’s say the Photos section is a little slow. So in the traditional HTML model, if it’s slow, you’re stuck on the server, trying to send the HTML for it, and you don’t have the data yet… You can’t really skip over it. You’re already in the HTML. You’re kind of stuck there. And then this idea that Facebook used in its PHP setup was to have an abstraction that lets you break down the page into independent sections that were called pagelets. And each pagelet could have its own data dependencies, CSS dependencies, JavaScript dependencies… And the idea was to send it kind of breadth first. So you kind of get the [unintelligible 00:44:46.27] of the page with the shimmers for pagelets, and then each pagelet can stream in later, and it sends a little bit of glue code to just put it in the right place in the DOM… So it kind of keeps revealing with nested – like a train schedule; more data arrived; let’s reveal a bit more. More CSS arrived, we’re ready to reveal this piece.

And so this is something we integrated with React, and this is what Suspense is. I mean, Suspense in general is just an API that lets you see “This part of the tree, if it’s not ready, show a glimmer. Or show a placeholder, or show a spinner”, or whatever you specify. So it’s a very designery concept. It’s how designers think about loading states. They don’t think about promises, or data fetching, they just think about “Here’s a part of the screen. If it’s not ready, show this fallback. Here’s the fallback I designed.” And it’s such a powerful concept, because if it’s declarative, it means you can build technology that understands what to do if something’s not ready. So one thing you can use it for is this kind of streaming, where if on the server you encounter that a piece is not read, you send the full back, and then you kind of load – you send the rest of it later.

So this is how React solves this problem with – previously, in traditional server-side rendering solutions, you have to download all JavaScript, just for it to start hydrating. By hydrating I mean this process of attaching the event handlers, and becoming interactive. And so it had to become interactive in a single pass, when all the code and all the data and all HTML has already been downloaded. But with Suspense – and you don’t need to do anything special for it. It’s just how it works. If you specify the Suspense placeholders around pieces of content that are maybe slower, React actually hydrates it in chunks as well. So it’s able to hydrate the first pass, where all the things outside - you know, photos, and about, and the feed become interactive, and then as a bit more code is downloaded, now it has the code for the feed composer, so maybe you can like posts. And all of this, of course, happens within something like 10 seconds. So it’s not about something super-long running, but it’s just chunked up, so that it’s able to do that in small parts.

Yeah, that makes perfect sense. I feel like that’s a little bit of the Astro islands paradigm as well, where breaking things up into smaller chunks allows for faster processing, and better prioritization of what should load first etc, etc. And browsers are pretty fast parsing JavaScript in general these days, but by chunking, you’re able to shorten that time.

Break: [00:47:41.27]

So all of this fun around server-side rendering… Okay, we have Suspense… And so where do we get to this RSC – how did React Server Components come into fruition? What problem are they – I mean, I think we’ve maybe even set the problem up pretty clearly… But I’d love to hear in your words, what problem are we solving by bringing this data fetching as kind of first class, as a React primitive?

Yeah, so this is an interesting question, because I think we have this background of “Here are things we’ve learned over the 10 years.” For example one thing is you want to be able to start [unintelligible 00:52:05.05] without waiting for everything to finish, every previous stage to finish. So you want things to be kind of chunky; you want to be able to send a part of the code and have the rest a little later, and so on, without waiting. So you have all these constraints of what a good solution should look like.

Another thing we learned is client server waterfalls are bad. So you never really want a solution that forces you – like, you go to the server, you get something back, you start rendering, and you’re like “Oh, I need to go to the server again. Fetch and useEffect, and go to the server again, get something… You continue rendering, and it’s like “Oh, we need to go to the server.” It’s not efficient, but it’s how a lot of single-page apps end up working.

So we have all these constraints on what a [unintelligible 00:52:55.19] should look like, but actually, I like to think about React Server Components as not some kind of optimization, or not just some way to make things faster… I like to think about it as combining two mental models that have been pretty successful in the past. One is the traditional request/response mental model, that we liked in PHP, or Rails, where you’re in the programming environment that has the data, so you can easily query it, you can access it directly… And then the other paradigm is the traditional React paradigm, where you’re on the client, so you can instantly respond to interactions. And so React Server Components kind of tries to answer the question “What if you tied these two paradigms together, and you could create components that span both of these worlds?”

As a concrete example - you know, it doesn’t even necessarily require a server that runs JavaScript, because - you know, another thing we learned over those ten years is if you have some code that’s able to serve a request, [unintelligible 00:54:04.11] also runs that code during the build, in some cases. So that’s how static generators like Gatsby, or Jekyll in the Ruby ecosystem, work. You can have a server, but you have a tool that calls the server during the build, with predefined file folders, or slugs, like for a blog, and then you have the final product, and it’s enough to have a static server that just serves those files, so you don’t actually need to run a server.

So React Server Components are kind of similar, in that you could run a server with them, but you could also run them during the build if you’re building something like a blog, where you know ahead of time what kind of routes you have, and you just kind of pre-render them… But I think the main thing that’s important there is - for example, if I’m making a blog with React… Let’s say I want to display a searchable list of my blog posts. And let’s say, for example, that I don’t actually have too many blog posts, so I don’t need to run a server that executes the search… I really want it to be a local thing, where - like, I have a textbox, I start typing into it, and it filters… Kind of like an SPA - I just start typing, and I already have the data, it just shows the filtered posts.

So the thing is, in React, I really want to be able to take things on the screen, and make them into components. Just like a designer thinks about the user interface – the designer doesn’t think about server, or client, or any of that jazz. The designer doesn’t care where the data is coming from. They just say “Here’s an article. Here’s a comment box” or “Here’s a searchable list.” But the problem is that in traditional React, a searchable list that I described is kind of an impossible component, because it depends on data from two different computers. It depends on the current state of the input, so it depends on what you’ve typed… And I as an author, I just can’t know that. I can’t know this ahead of time. This is a computation on your machine. But then it also depends on the list of blog posts, which is something that your computer can’t know, because that data is mine. I have to pass it to you somehow.

[00:56:22.27] So if you had to write a component like this in traditional client-side React, it would have to accept all blog posts as props. So it would not be self-contained, because it would need that data to be coming from somewhere. So it’s not really – I can’t really have a searchable block list component and put it in two places, because I would have to somehow plumb the data into it. And so with Server Components the idea is that, well, what if the data could be coming from a parent component that just ran ahead of time on my computer? So the component execution kind of becomes split, where I can have a component that runs on my computer, that reads the list of blog posts, and it renders the component that will later run on your computer, that does the actual filtering. And it’s just the shift in mental model from like where is the data coming from? Because in traditional client-side SPAs, and this model, the data comes somewhere from the side. You kind of think “I write the component, it does some kind of a fetch, and the data waits for something…” But with Server Components, the mental model is like “Well, the data is just coming from a parent component, that already ran on the server, or during the build.” So the data always comes from above.

Yeah, so I think this is where I get a little confused, Dan… So you’re saying that the data comes from a parent component that calculates it ahead of time… But how do you calculate it ahead of time, I mean, if it’s dependent on input that you get from a user. I think that’s a little…

Yeah. So you can imagine, for example, if I’m talking about a searchable blog posts component, what I do is I split it in two. So there is kind of like a boundary between them; in React Server Components it’s called the ‘use client’ directive. But you can think of it as being similar as a script tag. So there’s this stuff inside the script tab - that’s the component that will run your computer. And then there’s stuff outside of it. This is the stuff that runs ahead of time. So maybe one way to think of it is you can imagine, if this is PHP and jQuery, instead of React on both sides, then you have the PHP side that enumerates the folders in my blog, and then it would render a script tag with my jQuery code, and pass some data to it. This is kind of similar, except you don’t think in script tags at all. You kind of write the component that does await [unintelligible 00:58:58.19] the files on the server, or during the build, and then you just say return your other component that is able to do the filtering and has your state in it, and you just pass ‘blog posts=blog posts’ to the component, and then in the child component, you just have all the blog posts as props. So you can filter them and you can use state there. So you think about it in isolation, here is like the first pass, and here’s the second pass. Yeah, I’m not sure if this is too abstract, but…

Yeah, definitely not too abstract, and I think it’s sinking in a little bit more… But yeah, go ahead, Eric, and we can kind of come back…

[00:59:41.00] So being on the this React journey for so long, the synchronous nature of React was the thing that initially I understood it; whenever you have – in my mind it was like “Okay, [unintelligible 00:59:54.01] then you probably want this thing to be straight in, straight out sort of deal.” Introducing promises, as we learned from the [unintelligible 01:00:03.11] it’s like, alright, now you have this whole complex state machine that you’ve got to deal, with error states and everything. But whenever I saw an async component with an await for data fetching, it clicked for me, because that’s always how I expected it to kind of work, and it just took basically years of workarounds, and basically wrapper components to effectively accomplish what I was already trying to accomplish within my code. I mentioned React Resolver before, but then what kind of ended up happening is we’d have a useEffect doing a fetch, and that component effectively turned into the spinner loader component on the server whenever we rendered and spat it out, and then it finally actually did the fetch on the client.

So to me, seeing async – was the async component usage, was that something that started working because of RSCs, or is it something that became supported because of Suspense? What architecture allowed there to be an asynchronous component? Because it still requires – because the async nature doesn’t need to be a Suspense boundary above anything that’s an async component with an await on the inside?

Yeah, so we currently only – I mean, in the future we might support some version of async components on the client too, but currently it’s only supported in Server Components. And a big reason for that is avoiding performance footguns… Because again, what you expect on the client in general is that you can expect instant interactions. So you expect that when you change some state, we’re immediately able to respond with some kind of feedback to the user. And so if you could put arbitrary async components into the tree, then we can’t really show a new consistent tree until they have executed. So that might introduce delays.

So the way the Server Components paradigm solves this problem is that all the async stuff actually happens ahead of time, on the server, or during the build. So you never have this issue where you change some state, and then it gets stuck because it’s waiting for something on the client. It’s more like a request/response model, where all the Server Components output is already pre-computed by the time you get the page – from your client perspective they don’t even exist; you only see the props that they gave you. So you just have props from somewhere, you don’t really know where they’re coming from. And then if you do a navigation, that’s where we do a refetch, and on navigation we can load the output of Server Components again for the next page, or for a refresh of the data… But again, all the async stuff kind of executes on the server, and then when you get it on the client, it kind of feels synchronous. So you just read them from props, you don’t really think about like waiting for something.

Got it. Yeah, because on the server you don’t have that consistency problem. It’s really only a single state that ever gets rendered. And that state comes from – I guess instead of a function of state equals the UI, is it like a function of the request, is maybe a way of thinking about it on the server?

Yeah, it’s kind of like a function of URL, and… I mean, you can also think of it as a function of the data, in the sense of – just like you read state on the client… Like, sure, it’s coming from React, but conceptually, it just reads some memory on your computer with a state, whereas some memory on the server, that’s probably da from the database, or something from a file read… Or even a result of fetching from microservices, but they don’t have to be exposed to the client computer. It’s just like UI is a function of data. It’s kind of like UI as a function of both, it’s just executed in two stages. First, all the stuff that depends on the data executes on the server. That output gets sent to the client, and that’s your normal React tree, that works as usual.

[01:04:08.10] Yeah. And for me that’s where it clicks, Dan. So essentially, there’s a remote call that’s executed from the client, that’s like “Go prefetch, go precalculate these things. Go render out this part of the tree, based on these inputs, and then send that back”, and that computation is done in the server. And so I think that’s the piece that I needed to hear, because - you know, you mentioned this stuff happens ahead of time, but when you say ahead of time, it’s really ahead of time of the page fully rendering, right?

I mean, yeah, when you’re in the client-first mentality, you think of the client code as the beginning of the world…

Right, right, right.

It’s like “This is where my program starts.” So you think “Oh, if I need data, I need to call for it.” But the thing is this client program was already sent by another computer…

From a server…

Yeah. So all the data stuff could have just happened there, and be inlined into the stuff that gets sent to you… And that’s how traditional server-side rendering worked, is like if jQuery plugins needed some data, PHP could put that data into the page. So it kind of extends this idea that – another way to think about it is it’s kind of like sending JSX over the wire, almost… Except of course for first load you also want to send HTML. But it’s kind of like if you had one API endpoint, and the only thing that API endpoint could do is return, like “Give me a JSX for the next page.” And that’s what it kind of responds with.

Yeah. And that’s really smart, because you’re able to do more with less, and we’re able to do more earlier, and leverage this hidden server, that we don’t really think about, a bit more efficiently.

Definitely that, and also, it lets you think in components. So it kind of breaks down this – because usually, you think of these as two processes that are completely unrelated. Like prepare all the data, deal with some state… But in this filterable list example, it’s like specific data and specific state; I need it to render a UI. And so I can kind of compose these components together, and now I can have this filterable list component, that I can just render in different parts, on different pages, if needed, with different props… I just use it as a React component, but it’s able to access both the data from the server, and the client part is able to access the state, and that kind of stuff. So it’s about full-stack components that are composable.

You said something that I thought was actually interesting - I’m paraphrasing, but it’s to the effect of, you know, when we see a component, we see a client component as the start of it, or start of the world, or whatever. And RSCs I think clicked for me because it was always starting on the server. Static generation to me was like an optimization of “Well, okay, well, I’ll just perform that first request on the server, and cache it, and write it out.” So it always kind of clicked.

I think a lot of React developers came in at the single-page app time. And where it was all – I mean, I’m working on an app today that I think the codebase goes back six plus years, with React Router 3. And so whenever we see that, do you think that that client-first sort of experience history or mentality is a reason why there was like a knee-jerk reaction to [01:07:37.15] SQL call, or something like “Why are you doing a SQL call on my code?” I can’t remember how long ago this happened, but the fact that a React component could access the database within the component seemed to spark some FUD. Do you think it was that kind of client-first mentality that allowed that sort of mentality to take place?

[01:07:57.08] Yeah. I mean, part of it is – sure, using SQL inside a component on a conference slide… Yeah, you’re gonna make some people mad. It is kind of a troll move a little bit, but…

It got the point across, right?

Right. But I think sometimes it feels like maybe it gets the wrong point across, because people have an expectation when they see React code, that it executes on the client. And so if you see React code during a SQL query, you think of like “Is it calling SQL from a client?” A lot of people - for example, one of the misconceptions about RSC is that people think that it mixes client-side and server-side code in the same file. So that actually never happens. That’s something we don’t allow, specifically because it’s very hard to understand. That’s something that current solutions do sometimes. [unintelligible 01:08:46.18] Router mixes server and client code in the same file, remix mixes server and client code - the current version of remix does that. But in the future, with eventual, hopefully, adopting RSC, would like to move where we never do that. So in their C model we never mix server and client code in the same file.

But I think yeah, the knee-jerk reaction is partially just because when you see something shaped like a React component, you think that it’s something that has to execute on the client… But I think it’s like – you know in the Matrix movie, where Neo realizes that actually the world is not real, it’s created from another world… I think that’s a similar – if you’re client-centric, you write a component that like… What do you think sent this component to the browser? There was a piece of code that did that, whether it’s a static file server, or an actual server that emitted the script tag. There was some code that’s responsible for your component getting in there… So what if you had full control over that code? And what if you had a component model for that code as well, so that you could write components that kind of span both worlds, and that are able to pass data, and then you can reuse them?

Yeah. So Dan, what’s really interesting for me about better digesting this paradigm is - like, there’s this shift away from what we would traditionally do to make a request to go get some JSON, and then take that and rehydrate our apps, right? And you see this also with htmx, where they do this transclusion, they kind of skip that whole JSON serialization steps… This very much feels like that, but with React’s primitives. So how do we now just skip a whole bunch of steps and just make data fetching first class, build it into the component, and give you a way to do that in a more efficient way? That’s kind of what’s clicking for me.

Yeah, I think philosophically it’s kind of funny that htmx – it’s like, what if htmx had a component model? Htmx doesn’t really have a component model because on the server you’re expected to write templates that emit htmx stuff, and then htmx has a bunch of attributes that specify some client-side behavior. So what if you took – you know, htmx attributes are kind of like Angular 1.x directives. So what if we just turned that into React components, and that would be the client side? And then what if we took the templates that emit the htmx, and what if we turned that into React components, and that will be Server Components?

Yeah, yeah.

So now you have React on both sides, and the mental model is it executes in two stages. The server stuff executes first, that produces the JSX, that gets sent to the client, and that’s where state updates happen. And so state updates can always be instant, because this is the part of the code that only depends on state… And then the components that also depend on data - that is the stuff where you do a route or a refetch, or a server action, you do one of those things that are triggering a refresh, and then that re-executes the components on the server that are necessary, that sends JSX… And because it’s not [unintelligible 01:12:11.04] it can be turned into HTML; that’s what we do first render. But for next navigations, we actually don’t. We just send the tree itself. And so this, for example, enables you to have animations between these trees, or… It’s kind of like just receiving new props. You’re like “Well, I guess I got new props.” React re-renders it without destroying the DOM, so it’s just a way to get props from the server.

[01:12:40.19] Okay. So if we’re looking at the network… So if I have the Network tab open, what am I seeing here, using RSCs?

This is very interesting. I think it’s fascinating how it works. So I’ll first talk about the case of navigations after the first load, because first load is special. Because for first load we have to send HTML as well. So it has a program inside a program. We want to have the snapshot that the browser can display immediately, because - of course, the browser doesn’t understand React’s custom format. But then for navigations, we don’t need HTML, because we don’t want to replace inner HTML and loose all state, so we actually just send the React tree.

So conceptually, you can think of it as - like, what you’re gonna see is kind of like a JSX tree, but in a different format. So one way to think about it is – so if you take a tag, a div, you can write it as HTML, so you can write it angle brackets, div, or you can write it as JSON. So you could say [unintelligible 01:13:41.19] It has to be a string. We need to tell what kind of element it is. And then if it has some attributes, you could say [unintelligible 01:13:50.18] last name, something. So that’s like a JSON object. And so you can think of a React component tree, or actually as a DOM tree - you could think of sending it as turning it into JSON. So you could say [unintelligible 01:14:09.12] something, and there will be an anchor tag. So you can think of HTML as being expressible in JSON format.

Then the next thing is sometimes you also want interactivity in client-side code, so you need the client to know where to get that code. In HTML this is solved with a script tag. So in HTML you just have a script tag, with some file name, and then the browser will download it. And in our format, it’s embedded into the tags. So you could have [unintelligible 01:14:43.06] which is a built-in one, or you could have type counter. Except counter - it’s not enough to send a string, because the browser doesn’t know what the counter is… So really, we send an object that says “source”, the URL to the script, so it’s the same as the script source; it’s where to download that code from. And the module ID. So a counter, it’s maybe module number 20, in main.js, or chunk-something.js. And so this just tells React “Oh, here’s how I download this code for the counter.” And this is why React Server Components needs a bundler integration, because we need a way to ask “Hey, bundler, go fetch that chunk, and give us the counter component from it”, and so then React can use it.

So you really see this tree that’s kind of like an HTML tree, but it’s in JSON, and it has built-in elements like strings, and it has references - we call that a client reference - which is really just an object that says “Here’s where to download the code for this component. Here’s which chunk it’s in.”

[01:15:53.08] And then the last part that is important is we don’t send it as JSON, as a normal depth-first JSON object, because that has the same problem I described earlier, of like you have to drill down. So instead, it’s kind of like JSON with wholes, where sometimes you just have a whole that says “Whole number zero, whole number one”, and then the protocol actually sends them line by line. So there’s like “Here’s the whole number zero, here’s the whole number one.” And so this lets us progressively show that tree, and then the parts that are not ready, you can have your own Suspense boundaries that show fallbacks. And so this lets us stream, even if some data fetches are slow, this lets us send as much of the tree as possible, as early as possible, and keep streaming in the rest.

Wow… So we basically solved the problem that Facebook.com had many years ago…

This is fascinating. This is a good time to ask about the bundler topic, because I think one of the things I keep reading about is that “Oh, well, React Server Components allow you to send up less JavaScript to the client”, which I think is fantastic. And because we’re doing some of that compute off the user’s machine, right? So we can kind of keep the JavaScript that’s needed for that off the user’s machine, right? Like, duh. Can you talk about some of that a little bit? That’s such a fantastic side benefit. I don’t know if that was the intended goal, or if that was just a happy side effect… But I’m here for it either way.

Yeah… I think there’s a theme here, like in React early on - it’s built on a very simple idea. UI is a function of state, and here UI is a function of data and state that’s partially applied over the network. I know that’s a computer-sciency way to say it, but it’s just like a program that executes in two steps, and the intermediate result of the first step is being sent. Because conceptually, this is a very simple idea, and… You could think of PHP plus jQuery app is also – it’s a program for two computers, but these two parts can’t really talk to each other in some well-specified way… And we say “No, there is a way to talk to them. One of them passes props to the other one.” That is how they communicate.

So I think you do get a lot of happy accidents from this model just by the way it works. Like you said, yes, it lets you send less code to the client, because a bunch of logic could just – you could run it ahead of time… And this is maybe where a comparison to something like Astro is very appropriate, where if you think of Astro templates, they serve the same role as Server Components; they execute ahead of time. On my blog I have this funny feature where I show the color of my blog posts - it’s kind of like a gradient, so from newer to older, but the gradient is adjusted by how recently I posted. So you can see “Here are the recent posts”, because they’re in the brightest color, and then the old posts are closer to the end of the spectrum. And so I use a library that does color interpolation for that… But because I do this while generating the posts, I just do it on the server, and I pass the interpolated colors as props to my components.

So I don’t need to actually – yeah, but then if I wanted to, I could just move one line into the client component, and now this library would be on the client, and now it would be able to respond, to interact. If this was an interactive color picker, then it would make sense to run it on the client. It’s kind of this ability to shift things back and forth, that is really interesting.

And the other thing that I think is maybe less well known, but it’s actually also pretty valuable, is not only we can send – you know, some code now we don’t need to send to the client at all, because it just runs ahead of time, or on the server… But also, for the code that we do have to send to the client, we don’t have one giant bundle that’s always the same… And we don’t even need to – like I mentioned earlier, Next.js Router did the split by the route. So you send the code that’s used by a route. But with Server Components, a bundler is able – you know, this is more theoretical; current generation bundlers don’t take advantage of this variable… But in principle, you only need to really send the code that’s actually used, that’s necessary for the current request, or for a current page.

[01:20:34.07] Because this is another thing - at Facebook it was very important that if you send the code for the feed, you don’t want to send the client code for all possible story types, because there’s maybe 100 of them. Or if you’re doing a blog with client-side examples in different pages, you don’t want to send all of the client code whenever you visit the blog. You actually want to send the code that’s used by the current page. And so because Server Components execute on the server, and they return client components, and then the script tags are only sent for the chunks that are actually used by the output. So that’s kind of like automatic code splitting. And you don’t even need to write dynamic imports or anything. It just kind of falls out of the paradigm.

Oh, okay. Wow, that is so cool. What a really cool side effect. Yeah, it makes sense… Because a React Server Component could also have client components nested within it, and we don’t really need to even process – we don’t need that chunk until we are at this step of the interaction. So that’s awesome.

Obviously, this is gonna be a silly question now, because I think we’ve really beat this topic to death… But you do not need a “server” to use rack Server Components, right? This was a pretty big misconception, and this is because we’re able to use the server that’s used to kind of literally serve your app, right?

I think there’s different ways to look at it. There’s using React Server Components to the full, where you take full advantage of the paradigm. And in this case, it does make sense; some things are just easier to do when you actually run a server that can run some JavaScript code. But you can take away different things from the paradigm, because really, I think maybe the biggest misconception is people think of React Server Components as somehow changing React, because you get dropped into a different world by default. When you write an RSC app, you get dropped into the server world first, which is kind of like an Astro template, but it looks like [unintelligible 01:22:50.22] client world, and you’re like “Why can’t I use an event handler here? I expect to write a counter component and I can’t do it”, and it forces you to actually – you need to step into the client world to do that stuff. But when you start on the server, you can do filesystem reads, or database, and stuff like this. But again, RSC is an extension of the React programming model. So it’s not a replacement, it’s just “Here’s the client React that we knew, and here’s a complement to it. Here’s the other side that you can add”, and you choose how much of that side you want to add, and you also choose at which point it runs. Because if you want to have a completely static file server, like with SPAs, then of course, you can’t run any JavaScript code at request time… But you could run some at the build time. And so this is kind of generalizing what static site generators have been doing, except with React paradigms. So this is what lets me write a blog that does fs.read, and then I specify generate the server component output for this list of pages, because these are like pages on my blog. And then the build product is a bunch of JS, a bunch of CSS, and a bunch of HTML files, and just a bunch of this precomputed JSON-y things that the client can download on navigation, so that it doesn’t blow away the state of the page. Like JSON, essentially, but it represents React trees.

[01:24:25.18] So this is something you can totally do. But then if you want to take advantage – and you can think of every SPA as almost like… It’s kind of like a valid RSC app, with a single server component that just returns the existent app. So it falls into the model as well. Of course, there’s nuances about routing… You can’t really take advantage of it without the router being on the server side, because you don’t know what page is being requested.

To clarify, you said a bundler integration is required to make all this magic happen and work, right? So what bundlers are supporting this today, and what’s on the roadmap?

Yeah, sure. So this is also not exactly true, it’s more – again, to get all the benefits it’s designed… In principle, in theory, you could have an integration that puts all the client code into a single file, and then the bundler integration could be very simple, because then it would just concatenate all the client-side code… But that’s not really efficient.

The reason we need a bundler integration is because we’ve introduced this concept of directives. So there’s ‘use client’ and ‘use server’. They don’t actually mark client and server components. This is one of the pieces where the naming is introducing misconceptions. They mark the doors between the worlds. So ‘use client’ is kind of like a script tag. The rest of the imports from this point – any code imported from this file is going to get into a bundle. So ‘use client’ is like an entry point, “Here’s where the script tag starts”, and then anything imported from that is going to be in the script tag.

And then ‘use server’ is not for components, it’s kind of like a door into the server. If you actually run a JavaScript server, it’s only useful in that case; it’s not useful for static generation. But it’s where you mark an endpoint. So ‘use server’ is like “Here’s server code that’s callable from the client.” And so if you use something like gRPC, that is pretty popular these days, this is a very similar idea. Instead of writing the fetch post on the client, and then request on post, here, I’m gonna run this function, you just import the function, and if it has this directive, it means React will give you an a thing you can await, but it will actually post to that endpoint, and it’s just a way to call functions.

So this is the kind of features where you do the same things you could do with PHP and jQuery. You can send a script tag with a bunch of stuff, and then later you can call a [unintelligible 01:27:07.17] But really, these two things are represented as imports. So it’s like if your PHP site could import a jQuery component and render it, and then if your jQuery component could import a PHP endpoint and post to it. So this kind of integration requires a bundler.

So the question I have about the – so the [unintelligible 01:27:30.17] integration makes sense, and these new ‘use server’, ‘use client’ directives - I like how you put it, is like you can see ‘use client’ and think of it as a script tag. It’s just a point where the bundler will split off. When I was migrating from the pages directory of Next.js to the app directory, one of the very first errors that pops up is “Oh, you’re using react use state. That should be a client component. Add this directive.” So why is the ‘use state’, the React client side primitives not sufficient of a heuristic to go off of. Because it seems that early on, when people were moving to the app directory, they’d basically just search their codebase everywhere they had a ‘use state’ import, or ‘use effect’, they would put ‘use client’ at the top… But that’s not either, is it?

[01:28:18.20] Yeah, I mean, you can do it this way, it’s just a painful way to migrate. I think they now have it in the docs that the recommended way to migrate is you just take your entire pages directory… You know, in the pages directory, the way it was structured is you have this get server side props, so get static props. This is the part of the file that executes on the server only. And then you have this page component in the same file. So previously you were mixing server and client code in the same file.

And so in the app directory, the recommended migration is that you take this page component, you move it to another file. So that is the start of your existing tree. You put use client at the top of just that file; you don’t need to add it to any other files. You just put it into your entry point. And then your get server-side props - that is what now becomes a server component. So server components are really – like in Next.js, they serve the same function as get server-side props in the old Next.js, as like Astro templates. It’s just like this part that executes first. And so you really need ‘use client’ only in client components that are imported from a server component. It’s the place where things turn into JSON. It’s where, if you pass props down, they will become JSON, get passed over the network, and then they will be revived.

So I think that is how to think about migration, is that you don’t – I think people think of it as a per file, kind of intuitively. They think “Oh, I need to open all files, and put ‘use client’ on the ones that are client.” But it really, it’s more like you have the entrypoint into your import tree, so you have your page component or something liek this, you put ‘use client’ on top of that, and that’s actually enough. And then maybe later you kind of pull some things out of it.. Maybe you have some data fetching deep down, that you’re like “Oh, actually, I’ll just do this fetch above in the server component, and I’ll pass the result as a prop.” And so you kind of gradually can pull some things out of it, out of the client part to the top, but you don’t need to add directives everywhere.

Is there a reason why being tightly integrated with the bundler, is there not an opportunity for bundlers to skip the directive part? I mean, with the exception of the use server from the client, but - you render on the server, and the very first time you hit an interactive client component, which we know to have use date or use effect… Isn’t that the equivalent of you going in and saying ‘use client’? Is there an opportunity to basically have engineers in React, authors do less work and have to think about, I guess, the paradigm less? And the biggest shift is just going from client-centric to just starting on the server, and the interactivity is already built into React, and the bundler just needs to be a little smarter?

Yeah, this is a great question, and it kind of gets – some of this is kind of philosophical issues, where… You know, there are things we’ve learned, and one of those things is that actually being intentional about where the boundary is valuable. Because there were attempts to do something that spans both worlds, like ASP.NET Web Forms [unintelligible 01:31:37.08] There were attempts to try to treat server and client as this thing that’s like there is really no boundary. But it’s not really the right abstraction, because the boundary exists; it’s the network boundary.

[01:31:54.07] And so you want to know what exactly are you sending, and where is the point where I pass some props down, but actually that get turned into JSON, and later they’ll get turned back from JSON. And I want to be intentional where that happens, both because you need to be aware of – sometimes maybe you’re sending a huge object, and if you just did this a couple of layers of hierarchy above, you could just send just a little bit of information, instead of letting it explode into this object. In Astro, again, there’s a separation between Astro templates and client islands. And that is a good separation, because it lets you decide “Which world do I want to put things in?”

In principle, I think what you’re asking for is “Well, could the bundler decide if there’s use state in this component, and automatically insert use client there? But then the problem is not all components actually deal well with their props being sent over the network… So you kind of want to be intentional, like “Here’s where I make the cut”, but you also want to be able to move that boundary very easily. So in this case, it’s like you just copy and paste it, and move it to another file.

So it does take a bit of learning to – it requires building a little skill that is comparable to the skill you have to learn if you’re writing a PHP plus jQuery app, or an Astro plus React app… The skill is always there; it’s about where to make the cut… Except you can reuse code between both sides now, because they compose, because it’s a single programming paradigm.

That’s just such an excellent point, because being able to move the boundary… It’s not so much that’s something has state in it; it’s that you can even float it a little bit higher, too. So you’re in control over where that script tag happens. And I think that React has always done a good job of thinking of escape hatches, just out of the box. Not everything is gonna work as a React component, so we need to be able to escape out to the rest of the world, and be a good citizen.

So knowing that some props are gonna be serializable or whatever, and being able to basically not get stuck to where you can’t even adopt it, but you can just move that boundary - that’s really helpful to understand. So that distinction between the two of it… It almost reminds me of like the WebPack 2 days, of doing an async import, and that becoming a code split boundary.

Yeah. That is actually how it’s – actually, going back to Amal’s question… Because I haven’t answered it, but there was a question about “What is the state of support for bundler?” And kind of circling back to that, it’s actually very hard to retrofit this into existing bundlers, because again, it’s like a conceptual shift of a bundler spanning two applications, except that they can reuse code between them… But it’s two separate module graphs. For example, if you’re in the PHP world, you can’t really expect to access modules from the jQuery. They’re separated by this. When you’re inside the matrix, you don’t have access to the food from – I don’t know if you watched the movie… It’s like two separate worlds, so you can bring stuff from the outer world into the inner one, but you need to be diligent about how to cross it.

And so the first thing we released in 2020, when we released the first specifications for the React Server Components - which has changed since then, so we did a few revisions in response to… The first framework that adopted it was Shopify Hydrogen, and it was actually like - it ran into a lot of problems; some of them were unknown, some of them we just didn’t have a solution yet, and so they ended up abandoning it. But it’s actually their feedback that led to the directives… Because before that, it was filename extensions.

[01:35:51.13] But together with our first spec, we also wrote a toy version of a plugin for WebPack. It’s very slow. So it’s not production usable, because again, it’s very hard to kind of retrofit it into a bundler that was not designed for thinking of like server and client as two separate programs that have doors into each other. That is really the new paradigm here, is just, you have two separate programs, but they have these doors, and one kind of door is render a tag with props, and the other kind of door is call an async post-callback. So they were not designed for this, but we did write a super kind of simplified version of the WebPack plugin, and it actually internally used the same mechanism that WebPack uses for dynamic imports… Because what we need is just – we need to create these chunks for… You know, each use client we discover is like a potential split entrypoints… So yeah, we just needed to create those files. And it’s like a level – ideally, if there’s demand for this paradigm, and if people really see its benefits, we’re kind of like [unintelligible 01:37:00.29] RSC is very ambitious, in that it requires some features in bundlers that don’t exist. And the idea is we can try to polyfill them with plugins, which is what Next is trying to do, but it’s super-convoluted… But this is also why Vercel has invested into Turbopack. So Turbopack is designed for this ability to have these split worlds that talk to each other… And Parcel is also designed for having this ability to have a combined graph from two different isolated worlds…

So I think as this paradigm becomes more commonplace, the hope is that the next – maybe it’s the person listening to this podcast; the next generation of bundler developers will treat it as a first class feature… And I don’t know, maybe in ten years it’ll be a standard, dynamic import will become a standard. That’s where we’d like to get to eventually. But for now, it’s this – WebPack introduced require.ensure before dynamic import. It’s kind of similar.

Yeah, so I was gonna ask about linting, because I am very curious to get your thoughts on if custom linting rules are going to help wrangle that, like ‘use client’, ‘use server’, all the directives, and enforce best practices there… But I feel like now I have a more interesting question around the bundler. So I don’t know, can you maybe quickly answer my linting question and we can move on?

Yeah. Okay. Yeah, so for the linting we want to fail at build as early as possible. So it’s not even just like linting; we use this thing called import conditions, which lets you specify that you run code in a different environment… So when you import React in the server world, in the server RSC environment, your state doesn’t exist. It’s not even just like it refuses to work, conceptually it’s not even an export. React doesn’t export ‘use state’ in this environment. So it’s similar to [unintelligible 01:39:02.01] jQuery and PHP world; it just doesn’t make sense, we want to fail early. So this is the level of protection we have now, is we just forcing you to add this direct– like, you can’t forget about them, because we kind of force you to add them. But one thing that’s missing is type enforcement. So one thing we want to do is if you mark a component file with ‘use client’, we want TypeScript to enforce that all its props must be serializable. So it shouldn’t be able to accept functions, and things you couldn’t pass from the server. But you can pass a server reference, a server action, because it’s not really a function. It’s actually an object you’re specifying how to call it. So I think types enforcement will – actually, I think it will help explain the paradigm, because when you see a type error, you’re like “Oh, I see what’s going on here. I’m crossing the network boundary, that’s why it’s saying that there’s a mistake.”

[01:40:01.27] Listening to you talk about what role the bundler plays, and how it’s a completely different paradigm from the way we’ve been modeling today, because there’s kind of two resolution graphs and whatnot… It’s making more and more sense to me why Next was really the first on the scene, with being able to support this. They have the infrastructure, they have the engineering power, they have all the things. They’ve got all the all the pieces in place. But at the same time, was it somewhat of an unfair advantage that they got there first? I don’t know, I’m just curious to hear your thoughts.

Yeah. So Next was not the first integration. The first integration was Shopify Hydrogen. Next was experimenting with Server Components for a while, but it didn’t really move to what we’ve seen in the Next 13 release, until maybe a year after, when Sebastian has – Sebastian is the person who led most of the design of modern React. So he came up with hooks, and with much of the design for Server Components as well… And so this started in, I think, if I’m not mistaken, 2017, with an internal post that maybe has a spicy title, “What comes after GraphQL.” Not in the sense of – you know, Facebook is using GraphQL pretty heavily. Obviously, it doesn’t want to actually replace it… But it’s just this idea of like, if we have to write these clients that download all the data, download all the code, and then apply the code to the data, you might as well do some of that work on the server. At Facebook, that was a pretty normal thing. Because previously, Facebook started as a server-rendered app, with a server component paradigm called XHP. So it didn’t really use MVC, like Rails; it was more like React Components, except they executed on the server. So that was one of the ideas - GraphQL, XHP, and Next.js would get server-side props. All of these ideas combined together.

Yeah, so the problem was we wanted to deploy Server Components at Facebook, and start – which is also, they’re hard to incrementally adopt, because you have to adopt it from the top, instead of from the bottom… So with Server Components if you have an existing app, then the pathway to adoption is not that you rewrite small parts of that app in Server Components, it’s more like you wrap your entire app and you put the Server Components layer before them, which maybe just renders your app. So it doesn’t do anything. But then you can start moving things a little bit into that world, from the client-centric world.

And so at Facebook this was not unfortunately possible, due to technical limitations of how our PHP and JavaScript – we would run a custom JavaScript engine, it was not V8… The way it was communicating with PHP was very different from how it’s usually set up at most companies in open source… And so we were faced with this choice of – like, we know how to make this work… Like, we have a solution for a bunch of features that we’ve had for a long time; we think we have something novel, we think we have something that combines the best side of client-server paradigms, like PHP plus jQuery, or Astro plus React… It has these old characteristics, things we’ve learned over the 10 years of streaming, and sending less code, but also just full-stack components, this ability to write components that are encapsulated and span both worlds… So we have this thing, and we just – we can’t keep developing that, because… Like, Facebook was stuck, because of the custom bundler, custom JavaScript engine, custom setup between the server and the – and it was already very optimized. So it was kind of like in a local maxima. And then the team that – and I’m not assigning blame or anything, but it’s just, we needed help from the team that maintained the custom, all this bundling infrastructure at Facebook, and that team was actually busy, because they were all put on the end-to-end encryption project for Messenger, and there was no nobody who could drive this big, technical redesign of how all our data fetching works.

[01:44:19.07] And so the choice was “Do we sit on this technology for several more years, just because Meta is stuck? Or do we go somewhere else to complete it?” And so we didn’t want to sit on it, and so Sebastian left Meta, and the question was “Where can he complete the vision?” And the ask there is pretty big. It’s like, develop a new generation bundler, bet on this completely unproven technology, and… Yolo.

The thing that with Vercel… Vercel has kind of invested into just trusting Sebastian’s direction. So when Sebastian came to the Next.js theme, basically on the first week he was like “We’re gonna rewrite everything, because these abstractions don’t quite work anymore. And we need a new bundler, we need – all of these things need to be new.” And so that is a very big bet to make for a very successful product. And Next is paying the reputational cost, and Vercel is paying the reputational cost for “Yeah, let’s just try this completely new thing that’s unproven, and let’s prove it out, kind of in the fires of shipping to production.”

And that’s usually the process that – you know, if you’re consuming React from outside, that’s the process that happened at Facebook. So when React was developed – like, you didn’t see that process, because… By the time it was open-sourced, it was already pretty solid, so you didn’t see the early React. But this is kind of like seeing that process play out in the wild, and… Yeah, I think the biggest thing is just Vercel was able to allocate many full-time engineers, maybe ten people, to work on this full-time for several years, for something that’s not proven, because they believe in Sebastian’s vision, essentially. And parts of it are still kind of rough, but I think it’s getting to a place where it’s actually getting really usable and proving itself out.

Yeah, that makes sense.

He said it really well, too. He said, “For history revisionists, I went to Vercel and changed Next.js. I didn’t change React. The React stuff was already there pretty much.” And so I think that’s really interesting… So with Next.js being not so much the first one, or early adopter, but yeah, helping to refine and dogfood it, and actually put the resources behind it to make it a reality - is this going to be competitive, first mover advantage for Next.js? Or will Remix, are they having to play catch up, or other bundlers…? Basically, this is very much a React thing, but it has to have that buy-in. Is this going to create a bit of a moat around Next.js because of their investment in it, that others might not be able to really catch up to?

Yeah. I mean, I think realistically, that is the case currently. I think, not for technical reasons… You know, it’s kind of unfortunate, in the sense that technically, the work is layered very carefully, so that all the parts that are not Next.js-specific, they’re in React. So every feature is developed in a way – even things that people think are somehow associated with Next.js or Vercel, they’re layered in a way that there is leverage by putting it into React, so that other frameworks can build around the same concepts. Or you can put a component on Npm that would work in any framework that adopts RSC.

[01:47:58.06] That is the goal of this “Why RSC? Why not just go with Next.js?” Well, because we don’t think these concepts are actually specific to a framework; it’s just the concept of splitting the file between the two worlds. Or not the file, but splitting the modules between the two worlds.

And I think realistically, currently it’s just, the team barely has time to document all the user-facing stuff… So document what is the – for example for the wire format, we don’t document it, because we provide the reader and the writer for this format there in the React repo. They’re not in the Next.js repo. So in principle, anyone can use them, but you just have to know which folder they’re in and what the API is. And you can look at the tests. The tests are also there, but it’s just nobody has infinite time when things are on fire… And right now everything is on fire, because people are starting to use it, and they run into all the bugs, they run into all the missing features, and the top priority for the team is obviously just to make sure that this paradigm survives, which means just making it usable for end users.

But I think as things kind of – yes framework authors are poking and playing with it now that there is some knowledge. We have a group – we’ve had a group for a while, internal, for framework authors, where they can just ask questions, and we try to reply as fast as possible… But I think really, the thing that will take it to the next level, where people don’t feel like there is some kind of unfair advantage is just there needs to be a bundler that supports this, so that it’s easy… You take the bundler, you take the React parts of this thing, and you just go wild with that. And until that exists, it’s much harder to experiment, because you have to either write a bundler plugin yourself, which requires a lot of specialist knowledge. I don’t even know how to do it. So yeah, currently you can only do this if you’re willing to invest amounts into understanding how to make the bundling work.

But then with Parcel adding support that’s close to built-in, or a plugin that really fits into the architecture, with Turbopack hopefully getting stable, and hopefully being usable outside Next.js, I really hope they make it usable as standalone, but keep the support for directives. I think these things will help it propel more into mainstream, because then people will be able to play with it. And if you can just fire up a Node server, and just call this function and see the output, I think that’s where people feel like “Oh, I understand how this works, I understand where the boundaries are, so I don’t feel like this is specific to Next.js.” But I think realistically, it’s true that there is some proximity to – if you take the burden of trying things out first, then you also reap the benefits of kind of you do have a solution first.

Yeah… First of all, I just want to say thank you so much for this incredible backstory and history, Dan, because I think… You know, at least for me anyway, I empathize with Vercel taking the heat. Like you said, they’re taking the reputational cost. And Guillermo has been someone who’s always made big bets on the web, and he’s obviously someone who cares deeply about the web… And so I’m like “Wow. Respect for investing in this, and taking this big, big bet on RSC, and putting literal cash money behind it.”

I mean, there is of course a commercial angle, in the sense of…

Of course. Of course.

[01:51:42.23] And I think it’s sometimes maybe misunderstood. I think the end goal there is similar to the Apple angle of vertical integration, but it’s also a bit different, because it’s all open source. I think the idea is what if you designed the architecture with a deployment model in mind? And that is something that – at a place like Facebook, that’s obviously how it’s going to be. You have a whole team of infra engineers, they will think about “How do we distribute work between our data centers? How do we cache things? At which layers do we cache things?” and so on. And then smaller companies can’t really afford to think about this. And Sebastian, as an architecturally-minded person, cares both about “How do we design it in a way that it doesn’t run into the walls that we’ve seen over these 20 years?” We know PHP without caching will run into a wall. Client-side-only will run into a wall. GraphQL-only will run into a wall. So it’s kind of designed – like, how do you design the paradigm so that it can be distributed in a good way? And then Vercel is kind of like “We’re looking for a paradigm that can be distributed this way, because we’re actually a solution for distributed computation, so this fits perfectly.” So I think that is the interest… They want a paradigm that’s able to fully take full advantage of the infrastructure they’re building, so it makes sense that they want something that’s designed in mind.

Yeah, of course. I mean, it’s also just – like, from an open source sustainability perspective, open source is sustainable when you align it to business incentives, quite frankly. Just real talk, you know? So no hate there at all. There’s just so much that we didn’t have a chance to get into, y’all. We’ve been talking for like forever. I’m gonna wrap with just a couple questions… So the name, React Server Components - because we talked a little bit about the community FUD, and some of the misconceptions and whatnot. But do you feel like if you could do it all over again, would you, Dan Abramov - you don’t speak on behalf of everyone on the team… But would you, Dan Abramov, call it something other than React Server Components, given the amount of confusion that this has ensued in the community?

I didn’t see a better term. I still haven’t seen a better term. I think it’s one of those cases like in React, where we – and maybe it is a bit arrogant, but we kind of redefined what the term means… [laughter] Because you know, like with rendering - maybe it’s unfortunate, but we needed a word. And in React, rendering means just computing the UI, not painting it to the screen. But it’s just something we – now people use that word in the React sense. And I think it’s just one of those cases where we’re – I think we’re staying true to the conceptual meaning of server and client… Because it’s two programs. One program sends the other program to potentially another machine; there is potentially a distance between them, so the boundary has to be serializable. And yeah, one program serves the other program. But it doesn’t map exactly to the physical concept of server and client, because – well a server can be a client to another server, and so on. If I were to reintroduce this concept, I’d maybe talk about what we mean by the server and the client. Like, this server is the part that runs first, and that returns the client part, that runs second, and they can run… But as we talked earlier, even 2016, people already figured out you could take the client program, run it on a Node.js server to produce initial HTML. So we’ve already put the client on the server before. And then with something like Gatsby, there was an insight, “Oh, actually, you can run the server itself ahead of time during the build, if you know all the requests you want to hit.” So we also put the server into the build, at deployment.

[01:56:06.15] So these concepts are already kind of muddied, and from the point of React Components, it makes sense this component kind of serves this other component, so to speak. So I think the name is still right, we just have to explain what we mean by the name.

Yeah, no, that’s great. I’m proud of you for sticking with your guns down. That’s fantastic. We could have just started a whole new rumor on the show, you know?

Maybe I just don’t have to have the imagination…

I doubt it, I doubt it. So Dan, if people are like “Alright, well–” You know this better than I do. You know the circle of people who use React is much larger than the people who use Next.js, right? There’s tons of people who use Next, but the React community is bigger than the Next community. So for folks who are like “Oh, I mean, where can I get started? Where am I looking? What are official docs that I can be using and leveraging?” The rollout on this has been very unusual compared to some of the other releases that we’ve seen from the React team. Right? And of course, there’s been big shifts in the team itself. So now we have people from outside of Meta that are part of core, and I feel like as a result of that there’s more work in the – certain parts of the sausage are being done in the open, or being done at different places… So I’m curious, how do folks actually get started on this at this point? And then also, is there anything that we could have done, or you would have done differently with the rollout of this feature? …just given the FUD and confusion that folks seem to have.

Yeah, in terms of getting started, realistically I just think Next currently is the most complete implementation of the vision. So if you want to get an idea of how it was designed to work, at least by the person who originally designed it, I think that is a good way to look at it. Again, it’s still pretty rough, just in terms of the developer server’s maybe not fast enough… So there are many paper cuts, but I think that is the place to get the initial impression.

Do you think it’s production-ready right now, as of today, February 2024?

Production-ready is a very subjective concept, I think. Facebook used React in production way before most people would call it production-ready. There’s definitely pretty large companies using Next.js App Router in production right now, both hobbyists and big companies… But it does have – there are some features that are less baked, that are currently being fixed, but parallel routes, intercepting routes… There were a lot of bugs related to those that are being fixed right now.

So I think in a year, I expect it to be a lot more bug-free, and just doing the right thing… I think currently, it feels a little shaky in some places, and maybe slower. For just a developer, the dev server is a bit slower. So that’s something I expect to see with Turbopack fixed. So I think it’s ready for production in the sense of you can start building with it; it’s not going to change under you in some significant way. The concepts are stable. But I think maybe actually the biggest part is just – because the conceptual model is new, there aren’t really a lot of resources to explain how to think in it. Or there aren’t really best practices that you can just – it’s kind of like React in the early days. If you would use React in 2014, then I think yes, you can totally use App Router. If React in 2014 seemed too raw to you, and you would rather wait till 2016, then I think this is similar. Maybe you can wait a little bit and then give it a try when there’s more resources and more people understand how to use it, and it’s easier to find answers that are correct.

Yeah, that makes sense. That makes sense. And so in terms of like your own risk for – it’s not even risk; it’s like your own appetite for being on the bleeding edge, and your team’s capacity to do a lot more learning through maybe reading source code, and experimentation…

[02:00:23.03] I think not necessarily source code, but… You know, we’ve talked about things like ‘use client’, or ‘use server’, that are very misunderstood… And it’s just like, until there’s a couple of really good blog posts - the same way as React was pretty misunderstood in 2014… And then, there were some talks, there were some blog posts, there were podcasts like this one… And eventually, there’s enough knowledge between people in the ecosystem that they can help each other… I think that’s where it needs to get.

Yeah, that makes sense. Alright. And my last question - this doesn’t even have to do with React Server Components… If you could wave a magic wand for one thing that you want to be on the web, whether it’s a feature, or even in a library, what’s one thing that you wish was on the web, that isn’t there today?

Yeah. I mean, I’m pretty selfish… I like React, so I’m interested in React getting better… But I’d really love a deep first class support for animations. Because this is something you can already do with libraries, like Framer Motion… So it kind of feels like “Well–” You can use it, it’s already there… But similar to how Server Components kind of resolved a bunch of – like, it lets people compose. The biggest thing with React is we want to let people compose things. We want people to take different parts, written by different people, connect them together and have the result still make sense. Server Components kind of extends it between client and server, so you can have these Lego blocks that are spanning both worlds, but you can still treat them as components and compose them… And for animations, this is something I’d also like to see, where maybe the person writing the component – currently, with Framer Motion and animation approaches in most other libraries as well, usually the person writing the component has to be aware that it’s animatable… So you kind of have to express the animation at the leaves. Whereas from React’s point of view, we’d like people to be able to write components, and then you should be able to animate them from above, and kind of say “I’m just changing this state from gallery index one, to gallery index three.” And I also want to show this gallery item – the actual carousel items created by somebody else, I want to specify where the current item is placed”, and then somehow, you’d have an API… I think the the Vue Transition’s API is a step in the right direction.

I was just gonna bring that up. I was like “I feel like that’s the baby [unintelligible 02:03:01.17]

[02:03:03.18] Yeah. So we want that, but we want to integrate it with the component model, so that it’s also very composable, and you can put things together, written by different people, and animate them in a way that doesn’t break as you keep doing that and keep expanding. There are many small nuances of like “What if you have multiple animations at the same time? Does one of them wait for the other, or should they happen together? What if the state updates in the middle of the animation? Should we hold that state update back until it finishes?” So there’s all these small things that are not really composable if you think about them in isolation, but something like React could actually orchestrate it. And so I’d love to see that. Maybe in a couple of years…

That is so cool. And also today I learned Dan Abramov is like an animations dork… [laughs] Yeah, clearly, clearly, very passionate about animations. Well, Dan, again, it was an amazing – this was just such a mind-blowingly deep and dense and educational podcast discussion… So I really want to thank you and Eric for joining us today. For folks who are listening, it’s probably going to take a few lessons to get all the gems that Dan and Eric were sharing, but worth a few lessons. If you’ve stuck with us this long, thank you… And yeah, so as hopefully this part of the ecosystem continues to mature, we hope to be able to have more discussions on this, and continue talking about it on the show… And in the meantime, we’ll put links to a bunch of stuff that Dan has shared with us, so you can take a look at some really good blog posts, and some good write-ups on this topic… And yeah, feel free to use the discussions area on our website for any questions or comments… And yeah, thank you so much again, Dan. It’s been a pleasure.

Yeah, thank you so much for hosting, and for inviting me. And also, I apologize if – I know that some explanations were kind of long-winded, and I also don’t know which of them really work… So I would appreciate if the listeners or the readers - if you carried something away from this, write about it. Write about it in your own language… Because I feel like the underlying concepts, at a fundamental level, they are simple. But then there’s a lot of historical baggage in how they combine together that is more difficult. And so I’d appreciate if people could help distill them down in a better way than I could do here.

Yeah, that’s such a great call-out. Alright, Dan, so once again, another one in the bucket this week… And hope to catch you all next week, where we’ll be talking about something delightful as well, I’m sure. Alright, everyone, cheers. Bye-bye.

Changelog

Our transcripts are open source on GitHub. Improvements are welcome. 💚

Player art
  0:00 / 0:00