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

Vercel ā€“ Zero 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.

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

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