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
- Changelog Beats! Dance Party
- Making Sense of React Server Components
- How Next.js is delivering Reactās vision for the future
- Simplifying Server Components
- React Server Components with Aurora Walberg
- āReact from Another Dimensionā by Dan Abramov at #RemixConf 2023 (YouTube)
- Data Fetching with React Server Components
- RFC: React Server Components (Github)
- Next.js 13: Server Components (docs)
- āData Fetching with React Server Componentsā initial 2020 vision (YouTube)
- JavaScript Fatigue
- Click to Component (Github)
Chapters
Chapter Number | Chapter Start Time | Chapter Title | Chapter Duration |
1 | 00:00 | It's (Dance Party!) time, y'all | 00:39 |
2 | 00:39 | Sponsor: Vercel | 02:43 |
3 | 03:22 | Hello, JS Party listeners | 01:36 |
4 | 04:58 | Welcoming Dan Abramov | 01:35 |
5 | 06:33 | Welcoming Eric Clemmons | 01:21 |
6 | 07:54 | click-to-component | 01:08 |
7 | 09:03 | React love stories | 06:39 |
8 | 15:42 | JavaScript fatigue | 03:32 |
9 | 19:14 | The evolution of React | 21:43 |
10 | 40:57 | The uncanny valley | 07:01 |
11 | 47:58 | Sponsor: PowerSync | 03:32 |
12 | 51:30 | First-class data fetching | 15:16 |
13 | 1:06:46 | Client-first FUD? | 05:54 |
14 | 1:12:41 | RSC in the networking tab | 03:58 |
15 | 1:16:38 | The bundler question | 05:10 |
16 | 1:21:49 | No server required? | 16:16 |
17 | 1:38:04 | On linting | 01:58 |
18 | 1:40:02 | Next & integrations | 13:42 |
19 | 1:53:44 | So... the name | 03:47 |
20 | 1:57:31 | The rollout: differently? | 03:24 |
21 | 2:00:55 | Dan's one web wish | 03:10 |
22 | 2:04:05 | Wrapping up | 02:09 |
23 | 2:06:14 | Next up on the pod (Dance Party!) | 00:55 |
Transcript
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.
Got it.
[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ā¦
Yeah.
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.
Our transcripts are open source on GitHub. Improvements are welcome. š