Advanced Application Deployment Patterns with React Server Components (feat. a DIY RSC Framework)

Rate this content
Bookmark

The developer ecosystem is always moving fast and this year has proved no exception. React Server Components can offer a significant improvement to developer experience and to application performance. But I think it's fair to say that this new server-first paradigm can be tricky to wrap your head around!

In the first half of this workshop, we'll explore React Server Components from the ground-up: building our own mini meta-framework to help us understand how RSCs work. We'll discover exactly what is produced by an RSC build and we'll connect those pieces together to form a full application.

Next, we'll deploy it! Cloudflare have also had a busy year too — Smart Placement, in particular, is a new technology that we've developed which fits the RSC model perfectly. We'll explore why that makes sense for our workshop app, and we'll actually deploy it onto the Cloudflare Developer Platform.

Finally, we'll build out our app a little further, using D1 (our serverless SQL database) to really show off the React Server Component's power when combined with Smart Placement.

You should come away from this workshop with a greater understanding of how React Server Components work (both behind-the-scenes and also how you as a developer can use them day-to-day), as well as insight into some of the new deployment patterns that are now possible after recent innovations in the platform space.

104 min
14 Nov, 2023

Comments

Sign in or register to post your comment.

Video Summary and Transcription

This workshop on React server components covers client-side rendering, server-side rendering with React and CloudFlare workers, and the use of workers for server-side rendering. It introduces the concepts of React server components, suspense, and the regional worker. The workshop also discusses the responsibilities of the global and region workers, optimizing bundle size, delivering HTML, and setting up a database. Smart placement is highlighted as a way to improve worker performance.

Available in Español

1. Introduction to React Server Components

Short description:

Hello, everyone. This is the first workshop on React server components. We'll cover client-side rendering, introduce CloudFlare workers, and explore server-side rendering with React and workers. We'll also dive into React components, loading data, building a compiler, and discussing smart placement. My name is Greg Brimble, a systems engineer at CloudFlare. Thumbs up if you've used React server components or CloudFlare. Let's get started!

Hello, everyone. So, this is the first workshop I've ever done, so please bear with me if there's any sort of technical hitches or anything like that. Hopefully, it's some good fun and we'll learn some stuff.

It's going to be very interactive. I have code that we're going to be working through. I have a couple of slides here just to sort of get situated, but it's going to be mostly like at a keyboard and working through some pretty technical stuff. And obviously, the focus here is React server components.

So, I was at React Summit in New York yesterday and we've now got this workshop, so happy days. React server components is obviously a pretty hot topic. There was a good chunk of yesterday's talks dedicated to React server components. It's really cool to see both all of the technological advancements that's happening in the space and also just everyone's interest in trying to adopt this, either because they're, like, users wanting to, like, jump right in and get all the latest, greatest features or if they're framework authors wanting to integrate it into their existing paradigms and stuff.

So, in this workshop today, we're going to take a little bit of a hybrid between those two sorts of users. So, we're both going to be writing server components as users of frameworks, but also we're going to be doing a lot of behind the scenes stuff to see, like, exactly how React server components work and what it would take to integrate them into a framework. So, if you don't follow absolutely everything in this, that's A, okay. It's super experimental, like, a lot of it's probably still going to change. I've just kind of, like, hacked around in this myself, so I don't really know what's going on, but, like, we'll see. Hopefully we get something out of this.

So, I have broken this down as best as I can. We'll see, like, one or two of them are quite chunky. So, we might need to even take a break in between some of these sections. But this is sort of roughly what the agenda's looking like. So, we're going to start off with just, like, React as we know it. So, looking at client side rendering. And then we're going to introduce CloudFlare workers. If you didn't already know, my name is Greg, I work at CloudFlare. I'm a little bit biased, but I think it's a cool piece of tech that fits into just, like, the web dev space really well. So, we're going to be running all of our React server components with workers today. So, like I say, we're going to start with client side rendering. React. Then we're going to introduce workers to you all. And we're going to then look at what it would take to server side render React with workers. And then we're going to stretch into the React components world. And so, we're going to actually start to load some data with React server components. We're going to build a compiler for React server components, like frameworks do. Then we're going to actually load some data from a real database. And then I'm going to discuss something like that we call smart placement, which I think is a really interesting architecture paradigm that really fits well with the React server components model. So, hopefully as we build this, you sort of start to see where I'm coming from with that. And, yeah. That's where we're going to close out this workshop.

I'm Greg Brimble. I'm a systems engineer. I work at CloudFlare, specifically on the product called CloudFlare pages, which is our full stack web app host, which is why I'm interested in all this stuff. It's not really a big surprise for anybody. I don't know how well this is going to work. But can we get, like, a thumbs up or something in Zoom for, like, people that have either, like, has anyone used React server components yet? Are you using Next.js and playing around with it? Or brand new to the topic? Couple thumbs up. Okay. And for anybody who's on Windows, I apologize. I'm on MacOS. So, I'm not 100% sure that everything is gonna work perfectly for you. But fingers crossed. It's all just like Node.js, so it should be okay. And can we do the thumbs up again for anyone who's, like, using CloudFlare at the moment? Just to sort of get a feel for how much I need to explain things. Cool. One person I see. Excellent. And I'm guessing, well, that one person, are you using workers by chance? Go with no. Okay. Cool. So, I got a fair bit to cover. And the repo for this workshop is bit.ly. I think it's also, like, GitHub.com. I'm gonna pop it in the chat. That's a much simpler solution. And the slides are linked in the read me of the repo as well. So, actually, let's just bring it up for everybody. So, here you can see my last minute changes, 33 minutes ago. Who knows what's gonna happen? The slides are right here. So, feel free to follow along with them if you prefer to look at your own screen or whatever. Let's go back. Couple of prerequisites.

2. Setting Up the Environment and Repo Structure

Short description:

Most people here already have Node.js and VS Code set up. To deploy along with us, you'll need a CloudFlare account. If not, you can do it locally. Set up a CloudFlare account quickly, verify your email, and have something deployed at the end. Clone the repo, run NPM install, and install the Wrangler CLI. You'll log in with your CloudFlare account. Node 18 should work, but Node 20 or 24 should also be fine. Replace the constant value in the constants TS file with your CloudFlare subdomain. The repo is organized into seven sections, each with its own project. If you encounter bugs, you can skip to the next section. Each section runs on a different port. Worker subdomains can be found in your CloudFlare dashboard.

I see most people here have got Node.js and stuff already set up. Get code editor, VS code. And the other thing is if you're wanting to deploy this along with us as we go, then you're gonna need a CloudFlare account. If you're not interested in deploying this thing, don't worry about it. You can do it locally. But I do recommend setting up a CloudFlare account quickly. It only takes two minutes. You just need to verify your email address. And then hopefully actually have something deployed and live on the internet at the end of this. So, that would be pretty cool.

As I'm just chatting, if you wouldn't mind, just getting this cloned down. Like I say, open it up. NPM install. And then there should be a dependency in there called Wrangler. Wrangler is our CLI. It's what we're gonna use to run this project. Because like I say, we're gonna be using workers. This is coming with all of that built in. But in parts, we're just gonna be using it as a way to serve static assets. So, it's nothing crazy. It's just a CLI that helps us with our tooling.

If you have signed up for CloudFlare or signing up, what's... Sorry. Sorry, Greg. I was gonna ask you for Wrangler. What do you log in with? So, when you run this, it should open up a browser for you. So, you just run this in the terminal. It should pop up a browser. And then you just sign in with your CloudFlare account. There is nothing specific in Node 20. So, Node 18 should work. I'm just saying what I used as I was working on this workshop. So, it's the only thing I can guarantee that does work. But yeah, I'm not aware of anything particular that I'm using Node 24. So, you should be okay. Like I say, if you are following along for and wanting to deploy this to CloudFlare, you'll need to log in with Wrangler. And you're going to want to replace this one value that we've got. This constant. In this constants TS file. Which I think is right at the root. Let's see. Yes, constants TS. If we open that up, you'll see we've got this one variable here. And right now, I've got that set to my account, obviously. But you can just go to this URL when you're logged into CloudFlare. And then inside bar, there is a whatever your subdomain is. And you just grab that and pop it in here. And then we'll be all set to deploy to your account rather than mine. And then that's it. So, like I say, it took a couple minutes to do that. And if anyone is struggling with any of the setup steps, just holler. But I'll give you just, like, two minutes or so to get through all of that. And then, like I say, we've broken this up into, like, seven different sections. And so, we can get a start with those in just a minute. I'll quickly walk through whilst people are getting set up how this repo is organized. So, we have the most interesting folder here is the exercises folder. Like I say, we have seven sections here. And each of these sections are their own little project. And so, they have, like, a package.json at the top of them. And they're all basically just duplicates of each other. And so, this is gonna be really quite nice. Because hopefully, if you have any problems, you'll be able to skip to the next section and pick up right from where you left off without whatever bug it was that was pestering you. So, everything is kind of identical as you go along. Except, obviously, we've done the progress as you've moved from section one to section two. And then, if we have a look, when we're running this, so we're here in this, like, first section, we're running this on port 8000.1. And when you move to the second section, just to avoid any conflicts or whatever, we're running this on 8000.2. And that continues all the way through to section seven. So, where can you find the worker subdomains? So, you should be able to just go to your dashboard. Let's do this with you live. Dash.Cloudflare.com.

3. Setting Up the Repo and Account

Short description:

It was linked here. Everything clear about how the repo is all structured? One quick question I have. I do not have the right sidebar showing up with the subdomain on my Cloudflare account. Is this you just signing up for the very first time right now? If you go to the sidebar on the left here, like, are you able to click workers and pages? If you click on the create an application and you just click this big blue button, that might just create one for you. So, if you grab the something.workers.dev and pop it into that constants file, we should be all set. That's everything. We should be able to get stuck in. First one is number one. We're talking about client side rendering. Let y'all take a stab at working through this yourself. Happy to answer questions as we go. Feel free to keep going whilst I'm working on it or we can just skip over to the next one. Feel free to work through it at your own pace. This very much was just how React first started. We're just sort of getting a feel for how we're using ES build today. Starting off pretty easy.

It was linked here. So, if you go to just this URL. So, you just go into your account. And then on this sidebar down here, you should have your subdomain. So, just grab it from there. Everything clear about how the repo is all structured? That all makes sense to everybody?

One quick question I have. I do not have the, like, right sidebar showing up with the subdomain on my Cloudflare account. Ooh. Interesting. Okay. Is this you just signing up for the very first time right now? Yep. Yep. I just signed up. Okay. So, if you go to, do you have the sidebar on the left here? Like, are you able to click workers and pages? Yeah. Yeah. I have that. I have the overview. But yeah, I can create, like, a worker. There's, like, a few templates that are available. Yeah. If you go to, like, if you click on the create an application and you just click this big blue button. Oh, am I still? Yeah. Still sharing. This big blue button here. And then if you just hit deploy, I think that might just create one for you. And then you'll be able to see that this is being deployed to some random thing. That works. Something.workers.dev. So, if you grab the something.workers.dev and pop it into that constants file, we should be all set. Cool. Yeah. That makes sense. All right. Yeah. I have it now. Cool. Brilliant. Okay. Cool. So, I think that's everything. We should be able to get stuck in. Everyone ready?

So, let me reduce the size for y'all. Like I say, it's breaking up into a bunch of sections. First one is number one. We're talking about client side rendering. So, if you actually go into this in your repo locally, we've got this readme inside the exercises number one folder. And we set out a couple of goals that we're gonna do in this section. And then we go into the detail on exactly what it is we're doing. So, my plan is to let y'all take a stab at working through this yourself. And then, like I say, happy to answer questions as we go. I'll give you a few minutes. And then I'll quickly run through it myself. We can take some questions on this section. I'll maybe demo something or whatever, and then we'll move on to the next section and just rinse and repeat. So, whenever y'all are ready, feel free to open up exercises. One client side rendering. Open up that readme and get started with this first instruction. Okay. Cool. If you're not done yet, like I say, don't panic. Feel free to keep going whilst I'm working on it or we can just skip over to the next one. This is obviously still gonna be available on the internet after this workshop. So, feel free to work through it at your own pace. So, this very much was just, like, how React first started. This is, like, create React app style. Like, in the world of JAMstack, almost 10 years ago sort of time. And we're just sort of getting a feel for how we're using ES build today. And starting off pretty easy. So, I'm just gonna, like I say, work through this real quickly for anyone who wanted to see me do it.

4. Creating HTML Page and Introducing Workers

Short description:

We start by creating an HTML page and serving it statically. Then, we write React code and bundle it using ESM. After the JavaScript finishes downloading, the HTML gets replaced with our client-side app. We also address a question about the NodeMon field and introduce workers, writing our first worker that runs in front of our app.

So, we're gonna start off with creating an HTML page. So, we'll just dump this into index.html. And we're gonna run this thing. So, I'm gonna exercises, one dash. This is going to, if we have a look at our build script, it's gonna copy the contents of our public directory into a new one, dist global. So, here we see our index.html. And it's going to serve it up on, like I say, 8000.1. So, we can open this up. And, oh, my goodness, that's tiny. But, yes, we have our static HTML being served. So, nothing crazy yet. But then we move on. And we actually start writing some React. So, we're gonna create a source directory and a app TSX. Dump this in. So, now we actually have some JSX and React. And then we need to tell our HTML to actually load this new script. So, we load up some as yet nonexistent JavaScript. We say, hey, load up this index.js thing. And we've also created this div root, which is where we're gonna put in the React app. And then we're gonna create this index.js. Grab that. Pop in our source file. Source directory. And now this should be all of our code. So, we just need to actually build the thing. So, we add into our build script a little bit more than just copying the files. But we now actually want to bundle our source index TSX. For the browser, we're gonna say, hey, we're gonna use ESM because we're modern and cool. Like I say, we're gonna bundle it and pop it in that same place. We are still going to copy all the static assets because we also have some image file here that we want. But if we save that, I think should restart. And if I refresh, hey, we've got our client side React app. So, you maybe saw for a split second there, the flash of content. Let's see if we can catch that again. And what I'm gonna do is I'm gonna go to the tab and I'm gonna slow everything down. We see that we're getting this HTML shell for a moment whilst our JavaScript bundle loads. Obviously, we're just doing this in development, so, it's like much larger than it would be in a production thing. But after a moment of this, the JavaScript finishes downloading. It executes. And then the HTML gets replaced with a our client side app. And there it is now. So, if we actually look at the HTML response that we got, we can see this maybe a little bit more clearly. This is still the HTML document that we wrote. This index JS that we request is our full massive React bundle. It's got all of React code and somewhere near the bottom probably is going to be, I'm guessing, our app. So, yes, here it is. This is our paragraph, our hello world from client side rendered React. So, like I say, pretty straightforward. And just where we're kicking things off.

Just checking the questions. Why could the NodeMon field? Okay. So, yeah. I've set up NodeMon to automatically watch the files of your project and also, like, the build script and stuff. So, it should be automatically restarting if there's every time you save the file. And if there's maybe like an error in the file, it might fail to build or something like that. It should fix itself whenever you, like, fix the problem. But if not, if you're having an issue at any point, just feel free to kill the process and restart it. It should be okay. If it's still having issues, there's probably something wrong with your code. Moving on.

So, a couple of people said they were using CloudFlare. But I know it's new to a lot of y'all. Let me flip back to slides. So, this section, we're just going to introduce workers. We're going to write our first worker. It's not going to do anything with React yet. It's just going to be something that we run in front of our app. If you did sign up for CloudFlare, you can deploy that and see it live. And then, yeah.

5. Creating First Worker and Deploying to Cloudflare

Short description:

Feel free to jump into section 2 and get started making your first worker. Just a couple of setup things. Click on the visit site to get the proper URL. It can sometimes take a minute or two for the new domain to become available. The worker will run there and return back a response. We're within 50 milliseconds of 95% of the world's internet connected population. Hosting on Cloudflare is not a terrible idea.

I'll talk a bit about afterwards, like, why this is interesting and how that sort of relates into stuff. So, feel free to jump into section 2 and get started making your first worker. Again, not a very big one. Just a couple of setup things. I returned the URL, but I didn't access anything. I had to go through the CloudFlare UI and find out. Click on the visit site to get the proper URL.

Right. So, yes. I should have added a note. It can sometimes take a minute or two for the new domain to become available. So, hopefully that fixes it in just a minute. Brilliant. Anyone else who's actually deploying this? Give it a moment. Sometimes it can take a second for all the DNS and all that sort of stuff to spin up. But should get there in the end.

Okay. Cool. I'm gonna just jump in myself and work through it. So, first thing we do is we create this global worker index TSX. And so, this is maybe a bit new to folks, if you haven't done workers or any sort of edge runtime stuff before. But this export default fetch is a pretty common pattern now for how you sort of intersect requests. And so, what this is basically saying is it's saying, whenever a request comes in and hits this worker, we want to run this block of code here. And we have some types here at the bottom which are just saying, like, hey, we've got this assets thing available to us. And so, we'll get to that in a second. But we start by just looking at the incoming request and say, hey, what URL are you trying to hit? We say when you're coming to slash date, then we want to respond just like an API would with some sort of, like, programmatic response. Otherwise we're gonna do env.assets and we're gonna defer out to the static assets that we've got behind this worker. So, like I said, it's a pretty stereotypical worker. A lot of them work in this middleware fashion. And we just need to build the thing. So, we grab this and we pop this into our build script. So, we're now not only building our client side app, but we're also building our worker. And we need to actually run that thing. Build worker. We'll be able to keep these open. We'll stay between them. Then we should be able to come out of the first exercise, go into the second. We do npm run dev. Because this is using Wrangler, when we open this up now, we still get our client side React app as before. But now if we go to slash date, we'll get it back, our programmatic response. And of course, this is staying up to date with the date as I refresh the page. That means our worker's working. Great. We set up a pages project. So, I've already done this, so I'm just gonna skip this step. And we add in a couple of things to our scripts and package.json. And what we're doing here is mostly just the deployment stuff. So, we get this. So, we're saying, hey, before we do a deployment, we manage to build a site. And in order to deploy it, we take that, like, directory, the public directory, basically. We say, hey, we want to deploy it to project we just created. And what this will do is it will deploy the app to Cloudflare's network. And then that will upload all of our static assets. It will upload the worker. And then if I open this up, fingers crossed, we have our client side app working. And stupid Zoom. We can go to slash date on it and see our worker as well. So, this is just like we were doing it locally, but now it's actually on the internet, which is pretty cool. So, let me close both of those. And open this up. So, when I say it's running on the internet, it really is. This is what Cloudflare is probably most famous for. We've built this massive global network. We have data centers all around the world. And any user from anywhere can just connect to their local data center, whichever one is closest to them. And that worker will run there and return back a response. It means it is really fast for pretty much anyone accessing this all around the world. Specifically, this is very cool. We're within 50 milliseconds of 95% of the world's internet connected population. Regardless of what type of business you're working on, if you've got users around the world, hosting on Cloudflare is not a terrible idea.

6. Introduction to Workers and Pages

Short description:

We talked about workers and where to learn more about them. Pages and workers are being used interchangeably in this workshop. Pages serve static assets, while workers power the compute.

We kind of talked a bit about workers. So, if you want to learn more about workers, this is the place to go. It's the developers.cloudflare.com. We got all of our API documentation, what you can do in a worker, some guides and walkthroughs, that sort of thing. More information about Wrangler. And then one thing we kind of just brushed over was the fact that we're actually using pages. Pages and workers are on the path to converging. It's taking us a while because they're very complicated. But we're kind of just using them interchangeably a little bit here in this workshop. So, don't worry too much about the specifics of when we're using what. We're using pages to serve the static assets and workers to power the compute. Again, developers.cloudflare.com.

7. Using Workers for Server-Side Rendering

Short description:

Workers can be used as middleware or to deploy entire apps. We'll start using workers to server-side render our React app. If you have any questions, feel free to ask. If you're having authentication issues, try turning off your VPN or creating an API token. We're using React NM because React server components are experimental. Make sure to follow the steps and update the necessary files. Rworker replaces the example with a server-side rendered component.

Okay. So, those are the two introductory sections. And let me see. Sorry, there was a couple of questions. So, workers are just like middleware, yes. They can be. That's sort of how they started. Very much in this middleware fashion. They like sit in front of some upstream host. But more and more people are deploying entire apps on workers. And that's kind of what we're doing here. So, there is no server. It gets deployed all of these locations and you set it and forget it. Which is really what's so interesting to me about this architecture. If there's no other questions on that section, we'll move to the third.

So, this is like I say where things start to get interesting. This one is still relatively easy. I promise the later ones get a lot trickier. But we're gonna start really using workers here to actually server side render our React app. So, we started with like Jamstack, right? React app. And we're kind of now moving into maybe I don't know, five, six years ago when people started server side rendering React. And we're gonna do that on workers. So, yeah, feel free to come out of two and move into three. And make a start whenever you are ready. A couple more things happening here. But we'll go over it when we get to it. As always, just jump in with any questions if you get them.

Ryan, do you have maybe a VPN or something locally that's interfering with your connections? Basically what happens is like Wrangler spins up a local server and then you get redirected to Cloudflare Dashboard and then that Cloudflare Dashboard, once you do the authentication, it redirects you back to that local server with some like code. And it should like hand off that authentication information to Wrangler. If you're having issues, I think there is another way to log in. Let me check here. Okay. Yeah, there's maybe you maybe want to try this step. So, let me see. VPN turned off. Okay. Have a look and see if this is an option for you. And then the one other thing, if that doesn't work, is that you can go to the Cloudflare Dashboard, and if you go to your API tokens, you should be able to create one. And then you can just set this as an envar in your system, and that will hopefully pick up that for authentication rather than your token that's failing.

Why are we using React NM rather than Node modules? It's a very good question, and I kind of just sort of dropped that in here with the intention of coming back to it later. So, the reason we're using that is because, like I say, a lot of the React server component stuff is still experimental. And, in fact, I've had to tweak just one or two small things to make it work nicely in the workers' environment. And so, we just got this, like, fork here, basically, of the, like, Facebook React repo build just here locally that I can reference. And so, and what we're actually, I think the only thing we really use here is React server DOM ESM. So, feel free to have a poke around, but we will get to it later. Like I say, it's just a couple of tiny things I had to tweak just to make it work nicely. But I do hope that we can, like, once this is a little bit more polished, generally, we'll have this upstreamed. And so, this won't be necessary. When you click the link in the browser, it says make sure that you've got this div in your HTML file. Okay. Sounds like you've maybe missed a step somewhere. Let me see where that's going to be coming in. So, we're in the third step. You need to take a look at this step here. So, once you run npm run dev, things don't work, and maybe it's a little bit broken. You need to grab this source index TSX. Exactly. Thank you, Phil and Cedric. And that is just one more thing that we need to update. Okay. So, I'm going to go through this myself now. So, Rworker is very similar to how we had it before, but we're now just also replacing our date thing, which is an example, with an actual server side rendered thing. So, we're going to pull in some React libraries, React DOM here, and this handy function which turns a React app into HTML. And so, this is producing a stream of HTML for us. We're just going to say, hey, browser, when you see this, it is HTML. Trust us. As before, serve static assets otherwise. I'm going to open this properly now.

8. Updating Source App and Handing Off Control

Short description:

We update our source app to be in charge of the entire HTML document. We add a new counter component for server-side rendering and client-side interactivity. Source index is simplified by replacing the entire document with our app. After delivering the server-side rendered document, we hand over control to the client. The client loads index.js and hydrates the app, making it interactive. React server components blur the line between server and client control. This is just the first concept of handing off control. Any other questions?

As before, serve static assets otherwise. I'm going to open this properly now. We're going to what do we do here? We oh, yes. We update our source app to no longer just be the whatever this was, just like a couple of elements inside the DOM. We're going to actually make that in charge of the entire HTML document. And so, like I say, this might be looking a little bit weird for people if they haven't used React in a server side rendering app before, but it's totally valid. The things we have to do are in the like source index, which we'll get to in a second.

A new component just for fun, which is our counter. And this is just to make sure that our server side stuff works, but also we're still able to hydrate the app and do client side interactivity. We're just adding this to make sure that's all still good, and then we actually add that to our app. And then, like I say, source index gets a lot simpler, because no longer do we need to find that div specifically. We get to just replace the entire document with our app. And then finally, we just need to this is the handoff piece. So, we've done the server side rendering, we've done the client side like hydration piece. We just need to actually say once you've delivered the server side rendered document, you need to hand over properly to the client. So, it loads in our index.js just as before. And so, now I think that was everything. Let's run this myself. Section 3, Dev, and if I open up 8003, yes, here we go. So, we've got our server side rendered React, which is very cool. We have our client interactivity. Everything seems to be working just fine. So, if I open up DevTools again, we'll disable throttling. Don't need that anymore. But we'll take a look at the response that we're getting back, because it is interesting. If you've never done server side rendering before, you'll notice here that our client, like, component, the counter, is just getting this default value in this HTML. So, if we had JavaScript disabled, that's what we would get. If we were a search engine calling the page, we would see the page is running, we would see the page is running, we would see our default state of zero. And it's only once we load index.js and hydrate on the client that this becomes actually interactive and useful. I think that was everything. Let's see. Anything else in my notes? Yeah. That's pretty much it. So, this is just the first sort of concept that we've introduced of, like, handing off control. So, the control is at the server to start with when it renders the document, and it hands off control to the client once that document has been delivered. It's loaded the JavaScript. And then this thing entirely redraws the app. And now the client's in charge. So, React server components really blurs that and gets a lot more complicated. That's why we're starting with a relatively straightforward example of clean control. But, yeah, that's it so far. Any other questions?

I didn't really. I have a quick question, because I saw this was using, like, the stream, like, streams, as it was creating the HTML. But I didn't actually see, like, streams. I just see, like, one request coming through. Is it just because it's so small? Yeah. So, I think the render to readable stream, I think this thing, like, chunks on line breaks. It's really kind of bizarre. So, you could totally replace this with render to, I think, it's just render to string and get exactly the same functionality here. And like you say, our app is really, really tiny. We're not doing anything worthy of streams. We do very shortly. So, bear with me one moment. But, yeah, I just went with streams from the get go, because, like I say, we're gonna be using that in just a moment. So, rather than just chopping and changing all over the place.

9. Introducing React Server Components

Short description:

So, this is the first time we're really starting to use React server components. In this repo, we introduce the use server and client pragma, as well as suspense. We can add a proper server component by opting it into server components. This whole function is async, allowing us to perform actions like a weight fetch.

So, rather than just chopping and changing all over the place. Got you. So, this one is the same as the render to string. It's just that if you had, like, multiple docs or a lot of line breaks, it would break up the payloads to be smaller. Yeah. So, render to string will wait for the document to be ready. And then it will deliver all at once. Whereas render to readable stream, when available, it will send pieces just as they come. Yeah. That makes sense why I've seen people in repos with an in line after each file. Yes. So, part of that is just, like, defaults of prettier and stuff. So, I have that here. And I'm not sure if that's having any impact. Because by the time we bundle it and stuff, all of that is maybe being lost. But it will become very clear in just, I think, possibly even the next exercise. So, hold that thought. Okay. Cool. Yeah. Cheers. So, how's the pace for everybody? I've been going through this just kind of at my own speed. But are we all happy? Or too fast? Too slow? Happy? Cool. All right. So, the next section is actually introducing React components. And React before was entirely client side. But React components introduces a proper first class citizen for rendering data. Like, to fetch data. So, that's really, really powerful. And it's what we're gonna start to play with. So, have a look. Come out of three and go into four. This is where we start to use server. And so, really starting to get into server components. If you haven't done this before, it's maybe a bit new. But yeah. Take a go. And then I think after this section, we'll maybe have a break. We've been going for an hour already. Yeah. If you want to step out before that, feel free. But after this section, we'll have a 5, 10 minute break or something like that. Yeah. Make a start whenever you're ready. Has my camera broken for anyone else? It seems to have frozen for me. I thought you were just going for the firework effect. I think that crashed my Mac or something. Okay. I will try and figure that out whilst you all work on section four. Well, in the interest of time, I will make a start myself. So, like I say, this is the first time we're really starting to use React server components. And in this repo, in this repo. So, that's cool. Introducing things like the use server and client, pragma. And we also add in some suspense in here. Maybe some first time people are using this. Yes, you can update it to 50 seconds, rather than five seconds. But five seconds should be enough. Cool. So, all we need to do for our counter is we just add in our use client pragma. One day I'll keep the readme open. And then, like I say, if you just run npm run dev here, nothing changes. It isn't fundamentally magic. We're gonna have to add in all of this to our compiler, our ES build toolchain in a bit. But we can start to see where it gets interesting when we add use server to our app. And basically, just opt this thing into server components. And that will let us add in, like, a proper server component. So, grab this piece, pop it into todo. And, yes, the thing to note here, is that this whole function is async, which is not the case for standard React components. And because it's async, we're able to do things like a weight fetch, which is pretty cool.

10. Introducing Suspense and Handling Async Components

Short description:

The suspense component allows us to handle async components and provide a fallback while they load. We can see the SSR still works, and the loading fallback is replaced with the data once it's ready. However, there are still client-side requests happening, which can cause errors. We need to build this into our bundler to handle it properly. The suspense component wraps a renderable component, while the use hook is specifically for awaiting promised values. Removing the counter component from the app doesn't prevent React code from being sent to the browser.

Obviously, really blurs the distinction between backend and frontend, when you're able to do this type of thing inside your React app. And now we just include this in our app TSX. And we wrap the whole thing in a suspense. So, suspense, for those who aren't familiar, is just a way to deal with these async components a bit cleaner. You're able to provide a fallback, which is what's displayed whilst this thing is loading.

Yes, exactly. So, just a way to get onto that. Feel free to close the tab, if it's bringing down your internet connection. But, yeah, if I come up into four and I run dev. And open this up. Our app works. And we've got our todos at the bottom, which is great. We can take a look at our network tab. We should see the SSR still works. We're still, like, getting this back as HTML originally. This is gonna be great for search engines or whatever. You also maybe see some interesting stuff here. We've got this, like, template, which has got some sort of identifier. This is our loading fallback that we had. And then we have this, like, this div, which is hidden. What's happening here is the document first shows that fallback. And once the data is ready, it replaces it in with the list of dos. But we added in a delay here, saying, like, wait 5,000 milliseconds, 5 seconds, before actually returning a response. This is cached or something. Yeah. Maybe I do need 50,000. Did I mess that up? Not sure what's going on there. But, yeah, that's super weird. Right. We see this flash for a second. I would expect it to be five seconds, I'm not sure what's going on with the delay there. Maybe messed up the parameter or something. We see it flash with the loading and then we get the data swapping in, which is what we expect. But, yes, as somebody pointed out in the chat, we are still seeing these requests happening client side. And in some cases, it, like, just goes exponentially and crashes the app, which is why I said sometimes this could error for you. The reason it's doing this, our client side bundle still has all of our entire app, including the 08 fetch. Even though we marked this as user server, we're not handling that yet. This is still getting bundled to the client, and the client is trying to run it. It does its best, but, like I said, it's kind of wonky. We need to build this into our bundler. That's what's going to happen in the next step. Other questions.

Can I use the suspense component for any function that returns a promise? So, suspense is supposed to be wrapping a component. So, it, like, awaits its children. So, whatever you, like, use suspense for, it needs to be able to be renderable, I think. But there is another hook called use, which just looks like this. You import use from React. And this is just, like, useState or useEffect or whatever, but this is specifically for awaiting promised values. And so, I think we show that off later as well. And if you have just, like, data that you want to wait for, you can use this. Or if you've got an async component, you can just await for it directly. If that doesn't answer your question, let me know.

Is there going to be a delay for me, even on reload. Okay. Cool. I'm just gonna chalk that up to my computer being weird. So, nice. At least it works for somebody. If we remove the counter component from the app, no React code is sent to the browser. Um, I don't think that's true at the moment. Because we haven't done any of the, like, bundler stuff yet. It will be true. So, hold on just a moment. But I think if I remove this at the moment, we're still gonna get the logic for, like, handling the suspense and stuff like this. Let's see. Load. Yeah. So, we're still delivering all of React and all of our apps. So, like, counter won't be included in here. But it's still like we saw that thing loading.

11. Introducing the Regional Worker and Setting Up

Short description:

We're going to introduce a new thing for React server components, which will let us keep things isolated and think about our app differently. The new piece we're building, the regional worker, is necessary for React server components and runs on the server to handle the new functionality in React 18. We're adding a second worker to deal with it. I'll work through it myself and copy the code into a new folder. The semantics of the regional worker are slightly different from the global worker, as we define a base URL and a transform to set it up.

And so, for it to be replaced, it needs React to be able to know how to handle that. Okay. So, we've been going an hour 15. If there's no other questions on the section 4, then let's say we'll be back at 25 past. Give us all a ten minute break. If that's cool with everyone. And then we're gonna get on to the really meaty stuff, which is actually building this, like, proper compiler with ES build and stuff. So, it gets a bit hairy. Like, you see, we're gonna be at this one for, like, an hour. So, yes. Make good use of this break. And I'll see you all back at 25 past. Next section, like I said, is where things start to get quite hairy. So, a lot of this stuff is really behind the scenes. If you're just a user of React server components, you will almost never need to think about this stuff. It should be handled by the framework for you. But because we are interested in learning and we want to play around with this, we're gonna have a go at trying to do some of this stuff ourselves. So, we're gonna get reasonably deep into, like, ES builds, internals. And we're gonna really start to be cognizant of what it is that we're producing. So, before we started with just a client bundle. Then we introduced, like, the server bundle. And so, we produced a worker, which was doing the server side rendering and then we handed off to the client entirely. But the React server components model is a lot more flexible. And so, we need to just give a lot of thought into exactly what it is we're producing for each of our different, like, like, places. So, we're gonna start by introducing a third thing. So, we're we've got the server side rendering piece. We've got the client piece. We're gonna introduce a new thing for React server components specifically. It's gonna let us keep things as isolated as we can. And it's also gonna lean into why I'm talking about smart placement later on. It's it just lets you think about your app differently. So, if I cut all of this down and all of section 4 stuff, as always, read me here with steps to follow. A big warning at the top saying don't worry if you don't get it all. It's okay. It's, like I say, difficult. Like, hairy stuff. So, make a start. And then if I can, I'll make a little bit of an ad hoc suggestion, which I think is when you get to this bit, where it's saying, like, now that's a lot. We'll see how we're doing for time. But if you can, post in chat when you get to there. Now that's a lot. We've got this regional worker built. Let me judge if we need to take a break halfway through or whatever. But, yeah. Feel free to jump in and good luck. Like I say, feel free to just keep going if you're happy. But feel free to take a break with me if you like. So, when we introduce the server side rendering piece, think of that as just really a nice to have. It's optional. Obviously, there are tons of apps still out there using React that are entirely client side. Server side just gives you a faster, like, rendering of the page. It's better for SEO. And so, that's why people upped it. But this new piece that we're building here, this regional worker, this is necessary for a React server component. You need something running on the server to do all of these pieces with the new functionality that React 18 comes with. So, it's a totally different paradigm. And so, we're adding a second worker to deal with it. I'm just gonna work through it myself just up to that point. So, I'm gonna copy this code into a new folder, our region worker index.tsx and dump that in. And I'm just gonna grab the build script here, add it. And I'm going to build. And so, if I just plug this in. This is very similar to the global worker in some respects. If we compare them and zoom out a fraction, in both of them, we're importing some render to readable stream. And in both cases, it's like, importing our app and, like, obviously rendering it. But you see, like, the semantics are just a little bit different. So, in the global worker, when we're doing SSR, we're able to, like, bootstrap modules and it's kind of took care of injecting in the client stuff for us. And in here, we're instead having to, like, define a base URL and this transform thing. And this is about setting up the region worker. So, it has knowledge about where to find all of the components that it's going to inject all of the components that it's going to use when it's trying to render this app.

12. Understanding Global and Region Workers

Short description:

We've broken up start and deploy into global and region versions. Running the region build and start commands on a different port, we get a serialized DOM structure that React understands. This enables out-of-order streaming. The region worker is responsible for generating the serialized DOM. The global worker does SSR and converts the serialized DOM to HTML. The browser initiates the request, which goes through the global worker, RSC region worker, and back to the browser for client-side hydration.

So, what we can do at this point is I think actually, I think we need to do one more bit. Just copying the scripts. I'm gonna sneak ahead just a fraction. Dump these in here. So, all we've done is we've just added in we've broken up start into two things. Start global and region. And same with deploy. And we're just gonna run the region one. So, I'm going to write one. I'm going to do a build manually. What have I done wrong? I have messed up my imports. There we go. A build. Let me just make sure that's okay in the read me for all of y'all. No, I think I've dropped it. Okay. I'll push that up in just a second for anyone else. And run this build. And then I do npm run start for region. And this will oh, no. Okay. There's a couple of things I need to do. One more as well. Sorry. There we go. You see I'm running this on a different port entirely. This is 9005. Previously we were doing 8005. And if I just curl this, you see we get back a bunch of gobbledy gook. This is not HTML as we know it. And this is, in fact, just like a serialized DOM structure that React is like React owns this. It's something it understands. And you can see that we're kind of doing things in a funky order. So, the very first thing we do, like, what this is responsible for as we saw in our region worker code, this is supposed to be rendering our app. But instead it's returning this thing. And the first thing it does, it says, here's counter. Then it does some suspense. Then it goes back to the HTML and delivers a bunch of HTMLy type things. And then it does all of our to do's. And you can see there are these references throughout, like, l1, dollar two, dollar l3. That's referring to these snippets that are, like, tagged in this tree. And it's saying, like, hey, you need to slot this piece in wherever you find this symbol. And so, this is what's enabling our out of order streaming that you get with React. So, like I say, you're not supposed to be able to, like, read this. This is something that's internal to React. But it's there if you want to take a peek. And this is gonna be what our region worker is responsible for. So, we're gonna continue to have our global worker. That's gonna be doing SSR. We've now introduced this region worker that's gonna be doing RSC. And we're obviously gonna have the browser that's doing all the interactivity. I tried to sketch this out while you were all working through this. So, the browser initiates things, makes a request for, like, slash. First hits this global worker. The global worker, like I say, is gonna try and do SSR. But before it can do SSR, it needs to know, like, what's the app I'm supposed to be rendering. Previously we were importing the app directly in here. But instead what we're going to do is we're going to ask the RSC region worker for this virtualized, like, DOM, the serialized DOM. And it's gonna construct this and send it back. And it can do whatever it wants to generate that. In our case, we're querying some to-do API or whatever. It could be speaking to a database. It could be doing anything it wants. But the point is it generates that stream of serialized DOM. And then the global worker, whenever it gets bits and pieces back in that stream, it does the SSR and converts that to HTML and delivers it back to the browser. And then this thing will hydrate the client components. That's what this whole architecture looks like. And I just wanted to put that in your heads as you're going through the rest of this fifth exercise. Because, like I say, it's a lot to keep in your head. So, hopefully that helps to break it down a bit.

13. Configuring the Worker and Moving On

Short description:

Feel free to pick up from actually getting this build running and then setting up the config for the worker. Most of this is just stuff that I feel should be built into either node or esbuild directly. No, you shouldn't need a Cloudflare connector on this locally. You should all run on your own machine without a Cloudflare account. Just skip the deploy steps. If you're getting a port collision or something, you can just change these ports to be whatever you want. If you try npm run deploy, this is actually using the Cloudflare workers sub domain. Constant. If you're a brand new account, you may need to deploy a worker first. Click yes, yes, yes, yes. Agree. Once you've got that sub domain, you pop it in here. No dice. Okay. Well, maybe bear with one moment. We can try deploying like six. Six exercise. And it's clean slate. Because that's basically just like five completed. So, you might have luck there. Did that create a second worker. Stopped working after that. Windows error. Interesting about ports. Yeah, let me know what it is and if I can help you work through it. Okay. I think I'm going to start going through the rest of this myself. So, we made it up to running the RSC worker. Let's see where this is in this file. Yeah. So, we basically made it up to here. We had the Wrangler region toml. We had our new scripts. And we had our builder and the RSC worker itself. So, moving on.

And but I'll let you go back. And so we were just at this section here. So, feel free to pick up from actually getting this build running and then setting up the config for the worker. And we basically just got to here, actually. That's what we just ran. Like, we ran this in the build script. And it's 9,005. So, if you're wanting to peek behind the curtain even more, there's a couple of pieces, I think, in the build script where I'm loading from this utils directory, which is just up here at the root. And so, you can take a look at, like, what default loader with esbuild is doing. If you are interested. Most of this is just stuff that I feel should be built into either node or esbuild directly. That's why I pulled it out. But yeah. If you're wanting to get into the nitty gritty, it's all there. No, you shouldn't need a Cloudflare connector on this locally. You should all run on your own machine without a Cloudflare account. Just skip the deploy steps. And then later on, we do introduce a database. And again, just skip the remote pieces for that if you're wanting to just keep it local. So, if you're getting a port collision or something, you can just change these ports to be whatever you want. And so, it's maybe the nodemon autorunner thing. So, that's probably where it starts. Just try and, like, you got to change it here in package.json. You want to change the region starts on. Just change this to, I don't know, 5005 or whatever. You got to change it there. And then you got to change it in the build scripts. Yes, here in the region worker URL where you define this piece. So, just change that to whatever you change the other port to. I'm just going to give it another minute or two for a few other people to finish. Because I know it's a bigger one. Yeah. So, if you try npm run deploy, this is actually using the Cloudflare workers sub domain. Constant. So, if you log into the Cloudflare dashboard. Just go to this URL. You should be able to see your sub domain in the side bar. If you're a brand new account, you may need to deploy a worker first. Click yes, yes, yes, yes. Agree. Once you've got that sub domain, you pop it in here. Just replace my name with yours, basically. And then hopefully that's picking it up. But if not, let me know. No dice. Okay. Well, maybe bear with one moment. We can try deploying like six. Six exercise. And it's clean slate. Because that's basically just like five completed. So, you might have luck there. But if we can take a closer look later. Did that create a second worker. Stopped working after that. Windows error. I knew it was going to happen at some point. I apologize. Interesting about ports. Yeah, let me know what it is and if I can help you work through it. Okay. I think I'm going to start going through the rest of this myself. So, we made it up to running the RSC worker. Let's see where this is in this file. Yeah. So, we basically made it up to here. We had the Wrangler region toml. We had our new scripts. And we had our builder and the RSC worker itself. So, moving on.

14. Updating Global Worker to Fetch RSC Worker

Short description:

Because our RSC worker is now producing a serialized DOM, we need to change our global worker to fetch the RSC worker and render the serialized DOM instead of importing the app directly. We use ES build to dynamically inject the RSC worker. We fetch the region worker and use create from fetch to turn the serialized DOM into HTML. The global worker doesn't need to worry about use server and use client and gets all its information from RSC.

Where am I? Here. So, because our RSC worker is now producing this serialized DOM, we need to change our global worker, the thing doing the SSR, to query for that DOM. And to render that instead of just importing the app directly. So, if we have a look at what global worker was doing before, we were just importing the app and rendering that. So, we don't want to be doing this. Instead, we want to be fetching the RSC worker. So, we dynamically inject this in with ES build. You saw that in the build script. Further down here, we put in this variable, this very handy feature of ES build that you're able to just inject stuff in like this. So, we should be reading from the Cloudflare worker subdomain that you got set up. But maybe there's an issue with that. We'll check it out in a minute. And then we're still using render to readable stream. But we're now introducing create from fetch. And if we just brush over these little bits a second, what we do is we fetch our region worker. And we say, hey, we're just forwarding this request on. And for the promise that we get back from that, we call create from fetch. This is a React internal. And we're saying, hey, you're gonna get back this serialized DOM. You need to be able to then turn that into HTML. And that's what this is doing. The bits up here, these headers and stuff, this is just kind of a proxying through to RSC from the global worker. So, we don't need to pay too much attention to that. And then all we do is build this. And thankfully, this is a little bit easier to build than the region worker because it doesn't need to worry about the use server and use client. It's getting all of its information from RSC. So, we just add in this one thing I think is basically all we need to change. So, yes.

15. Understanding the Global Worker and RSC

Short description:

SPEAKER 1 asks Greg to explain how the global worker gets its information from RSC. SPEAKER 2 sets up the two different services and explains the process. The region worker returns a serialized DOM, while the global worker makes a request to the region worker and converts the serialized DOM into HTML. The RSC worker handles the server components, while the global worker handles the entire app and combines it with the source app. The RSC worker only has a reference to the counter component, while the global worker has all the necessary information to build the app.

SPEAKER 1 Sorry, Greg, when you say it's getting all its info from RSC, could you explain that a little bit more? What you mean?

SPEAKER 2 Yeah. Let me quickly spin this up. And then we can have a look at the two different services running and what they're getting from each other. So, I'm going to grab all this and pop this into global worker. And then I'm going to grab our updated build command. Pop that in here. And then I have some error. What's that? Oh, yes. Import. There we go. And then we update. Yeah, that's good enough to answer your question. So, if we run our build again in my exercise, got it up in here, I'm going to run them separately just so that we can more clearly see what's going on. So, run my region. And then in another one we're going to go into exercises, five. And we're going to run global. So, we now have two processes. We have our region worker running, and we have our global worker running. If we go into our region worker and open this up, we get back this serialized DOM. And so, we've seen this already. This has, like I was talking about before, all these references throughout it, saying, hey, we're using suspense here, we need to fill it in with this value. Here's our to dos when they're ready. All this other stuff. And then, fingers crossed, I go to my 8005 port, we should see server side rendered React. This is going to be a bit wonky because I haven't done the browser client piece yet. I don't know if that's going to work. Yeah. Busted. But the HTML you see is being delivered correctly. What did we actually load here? Yeah, just the document. So, let's have a little closer look at the code. So, what we're doing here is, we're making a request for slash. This is code that's running. We're just allow listing some headers. We forget about that for the time being. We see that from our global worker, from our SSR worker, we make a request to our region worker, our RC worker. We're forwarding on the request that we get. And then we're saying, hey, if we're looking for some HTML, we call this create from fetch thing. This fetch, like, data response promise thing will be that serialized DOM. And so, create from fetch turns that into HTML. If it was to log this out, I would be getting HTML stuff here. Sorry, that's a slight lie. Go away. And I'd be getting back a React app here. Like a React element. And then we turn it to HTML just here. Just below. So, it's still using the render to readable stream we were doing before. But if I was to log this piece, I'd be getting HTML. And, in fact, that is what the browser's seeing. That is this. That's just, like, what we get back. Would you say that's kind of like how we a lot of apps server side rendered the app shell itself. Would you say that's the same, that's what, like, would you use the same mental model for this piece of RSC? Because is it loading all of the static stuff? Or is it still loading a mix of server components and the client components? It's doing all of the it's doing the entire app. So, what it does. It's all the server components mostly right now. Yeah. And when it comes to a client component, let's see if we can find that. Let's see. Okay. So, the RSC piece, you'll see it just has this reference to counter. So, let's find where that is. Here it is. So, L1. All it says is just, like, to and nowhere else in here is the increment code or anything like that, like, that doesn't exist. So, the RSC worker is entirely the server pieces. But the global worker, we actually go back and look at the code, we're giving it enough information and enough in the build because we say, hey, we want to build, like, the global worker plus all of the, like, source app as well. And, hey, it's available where do we put that. We say, hey, it's available in this directory. We look at the code, like, the built thing.

16. Understanding the Worker's Responsibilities

Short description:

Here's our worker. It knows about the server components and can interact with third-party APIs and databases. It does the full server-side rendering of the app. The HTML response includes the client and server component code. The browser will be responsible for hydrating the client components only.

Here's our worker. Here's our, oh, my goodness, that's messy. Let's see if it's recognizable at the bottom. Yeah, here's our worker. We're saying, hey, do your create front fetch. And, by the way, here's where all of the components exist. This is our components, including our client stuff. So, the, if I go back to my drawing, wherever that was, here. This thing only knows about the server components. So, it's able to interact with, like, third party APIs, databases and all this sort of stuff. This thing knows about all of our app. That way it's able to do the full server side rendering of everything. What you get back is, where's this thing running? Here. We look at the HTML, we get back our client component code. It's just been SSR'd. So, like, it does exist. And we also get back our server component code, like, once it's been turned into HTML. So, yeah, you can think about it as, like, just, like, two different responsibilities. This thing's responsible for the server pieces. This thing's responsible for stitching everything together. And then I haven't done it yet, but I think some people have already. The browser will then be responsible for hydrating the client components only. Because this is now all of the HTML it needs. It just needs to make the pieces that are interactive, interactive by loading those client components.

17. Building the Client-Side App

Short description:

We've changed how we're building our client-side app. We don't bundle the entire app into one big thing, only the client components. We're also just including the necessary React node modules. We tweak the hydration process to only hydrate the client component pieces. This is a benefit of React server components, as you don't need to load the entire app on the client. We only load the pieces that are being interacted with. By doing this, we get the benefits of server components and client components working together. Performance gains can be achieved by shaking out unused code. React server components enable computation to happen on the server and deliver just the necessary piece.

SAUER MOYIN BASIN Yeah. Makes sense. Okay, cool. Thanks for going through that. Yeah.

ADDY OSMANI No problem. So, yeah. Let me just catch up here and do that bit. So, I'm gonna grab these two and pop them into my build script. And so, we've changed ever so slightly how we're building our client side app. This is just to say, like, hey, don't bundle the entire app into one big thing. Because all we care about are the client components. So, we don't want to bundle everything up. We're just gonna keep them separate for the time being. And we're also just gonna dump in our React node modules, just that little fork that I was talking about earlier, just because we've got the pieces we need. And I think that's it. Oh, no. One more thing. So, we need to, yeah, tweak just how we're hydrating basically. Because we don't want the entire app to hydrate now, we only want to hydrate just the client component pieces. And this is one of the big benefits of React server components. You don't need to load your entire app on the client, just the pieces that they're interacting with. So, it's a big improvement. Where before we were shipping, like, tons of, like, libraries, or rendering markdown or something like this. When really you've got a static blog post, you should just be shipping HTML. Where did this go? This goes into app. So, this source index is a little bit more complicated. You see we're using more of this stuff that helps us do the glue. And so, it's saying, hey, only fetch the client component pieces that we're interested in, basically. So, now if I run it, hopefully this works for me. Npm run dev. This should build. Spin up my two processes. So, we're still able to go to 9,006, 5. Hold on. 5. Yes, we still get this. We're still able to go to 8,005. But now, you see all of React has loaded. And if we look for it, we explicitly loaded counter JS. That's the only actual, like, source code we loaded on the client. And that just makes this work. So, we can go and we get all of the benefits of server components doing daily loading and we get the benefits of client components and their interactivity. Happy days. That all make sense to everybody? I take silence as a yes. I like this a lot. I wonder if we had, like, a bunch of interactive pieces on the web page. Do you lose the benefit of loading a lot of it? And it seems like just similar to a client app. But it's really helpful when there's only mostly small interactive pieces. Yeah. So, I think there's a couple of things there. And I don't know if you want to jump in and talk about that. But I think there's a couple of things there. One, the way that we're doing the client hydration at the moment is really naive. You would never load just this file. You would, like, bundle up at least all of the client components that are on the page. Just so that you can, like, shake it out and, like, cache it and stuff. And it's also, actually, like, I think we're still building everything. If I go to source, like, to do's.js. Yeah. We're still building the server components. It's just not actually being used. So, you would still want to bundle the client correctly. We're just taking a little bit of a shortcut here. So, you would see performance gains there where you're able to shake stuff out that you're not using. But also, it's just about shaving off pieces you just definitely don't need. So, like, that example of, like, I said, if you've got some blog post and you've written it in Markdown in a traditional create react app, you're shipping both the Markdown content of your blog and then also some library from npm to turn that into HTML. And that's, like, could be potentially quite large if you've got, like, I don't know, code highlighting and it needs to know all of your languages and stuff. Whereas, really, what it should be and what React server components enables is for all of that computation to happen on the server for it to turn it into HTML. You deliver it just that piece.

18. Measuring Bundle Size and Worker Optimization

Short description:

In this section, we discuss measuring the bundle size of the client-side and workers. We also highlight the importance of minimizing the size of the workers for optimal performance. Additionally, we mention the limitations on the size of the app that can be deployed to serverless providers like Cloudflare. Finally, we address a question regarding the code in the index.js file and explain the purpose of the browser script sections in the setup.

Means you can forget about library but your like button on your blog post still works. So, it's just about leaving behind what you don't need, basically. How do you measure an app's bundle size with the setup? That is a good question. So, there's a couple of things now. Right? So, we've got the client side, and, like, I say, the setup that we have in this workshop is super basic. Everything is still, like, individual. They're not bundled at all. So, how do you measure the client side bundle? Not easily at the moment. I guess you would just, like, sum up all of the scripts that you import at the client. I'm sure there's, like, Chrome tools which would help you with that. But you would definitely want to be doing this properly. If you're doing it for real in production. The other things to think about are also the size of the workers that you're producing. So, if you want these to be super performant and, like, globally distributed and all this sort of you want to generally minimize, like, them, too. So, it's quite nice that the region worker, the RSC thing is only focused on the server components and the global worker is only focused on well, in fact, that's probably the heaviest piece. Because it does both the turning client components into HTML but it's also got to understand, like, what it's getting back from RSC. So, this is probably the largest. RSC is probably the middle and then the client is probably the smallest which is nice for all of your users. It just means that you need to think about these. If you've got a massive app and you're trying to deploy it to a serverless provider like Cloudflare you might hit limits on how big of an app you can deploy. I think ours for workers is maybe 10 megabytes at the moment. So, if you're getting any bigger than that, you'd start to hit issues. But, yes, congrats. You've all made it through the hardest part. I hope that that was an exciting piece because it certainly was to me. You could hear it in my voice, I love this stuff. I think it's a pretty cool piece of technology. Server components, they're really pretty something. I still see the call to the JSON. I'm wondering how is that happening that I still have the index in my index.js, I still have the code to the todo. Ah, okay, yes, let's take a look. I do see that in the code for this global we are effectively packaging all the JS. I know exactly what you're talking about. Let me see if I can bring it up. Yeah, you shouldn't. So, the index.js that we had before, let's go back to the previous exercise. If we have a look at, if I just look at my built stuff, here I think it is. This is our full React app. It has everything in it, including, like you say, the await fetch. But if I have a look at the current one, I go to index.js, all we have here is the code to say, hey, go and get me these components. So, if we look at the app, like what it does, it loads index.js, which is that file we just saw. Then what's all this? It's going to be difficult to figure out what's, what, I think this is just oh, yeah, okay. So, it's loading like React libraries. React libraries, and then it's like localhost again. So, this is making a request with the text X component. This is the header saying, like, hey, go and get me this DOM. No, the issue was on my side, yeah, sorry. Okay, cool. So, yeah, all it has is the client component. Yeah, I forgot to restart the npm server, so it was still delivering the previous code, I guess. Cool. Like I say, the implementation we have at the moment is not, like, secure. I could still go to, like, todos.js and see it. We haven't done anything about, like, protecting our server side code. It just, like, I'm not running this in the current setup, which is nice. So, it's just proving out that you don't need to ship this code, because it's not needed. And there's a bunch of stuff that they're still playing around with in React core, like the new taint APIs and stuff, that's, like, ways to mark certain symbols in your code as, like, you absolutely cannot deliver this to the client or to the server, and to blow up the build if that was going to happen. So, that's still very much, like, in progress. So, work is still kind of feeling it out. Can you explain the browser script sections? Yes. So, this is another thing I kind of just tucked away, because I didn't think it deserved, like, highlighting. But let's have a look. Yeah. Browser React. So, in here, we have this kind of hack. And this is just saying, hey, like, load up, like, React experimental for me from this CDN. And also, hey, you need this other file, too. This is because we have fundamentally messed with how the client hydrates. So, before we were saying, hey, we're going to produce a server bundle, it's going to have everything in it, and we're also going to produce a client bundle that's going to have everything in it, and then the server is going to produce some HTML, and then once that's on the client, it's going to hydrate, it's going to redraw the entire page, and the client's going to take over. What we're doing here instead is a lot more piecemeal.

19. Delivering HTML and Setting Up the Database

Short description:

You still deliver the entire HTML, but only the client components get replaced. We no longer produce a single bundle. Instead, we produce each component individually and load them manually. This allows for piecemeal loading. In the next section, we'll replace our to-do API with our own database and explore how to pass platform primitives to our React app. We'll also discuss smart placement and its relevance to this setup. Let's move on to the sixth section, which focuses on setting up the database. Feel free to start working on it.

So, you still deliver the entire HTML, but the only bits that get replaced are the client components. So, we're not producing the same big bundle. So, we're not able to use ES build in as easy a way, which is why our index JS has changed in order to do this piecemeal loading. And our build script, we're no longer producing a single bundle. Let me get the other one up to compare and contrast. Yeah. Previously we were bundling everything, and we were saying your one entry point is the entire app, but now we're saying, hey, just produce each component individually, and we're just going to load them manually, and that's really what the browser scripts and the new index JS is doing. Does that make sense? Again, I'm going to assume silence means yes. So, holler if you want me to explain anything else.

Okay. Cool. That is wow, another hour gone already. Do we want to take maybe a five minute break? Because we're coming up to the end here. The final two sections go a lot quicker. So, let's say, meet back here at 25 past again, go and grab a snack or something. We're starting to come to a wrap up here. What we're going to do is replace our to-do API with our own database, just so we can see how that works and how we can pass, like, platform primitives to our React app and use that in our server components. And then I'm going to chat about smart placement for a bit and show you how that makes sense with this setup. And then we're done. So, the sixth section, let's go in here. This is just all about setting up this database. Just a few things to note when you're going through. Just to make sure you're replacing some IDs and stuff. I'm choosing a location that's far away from me. I suggest you do the same. But it's no big deal. And then hopefully we get through this and the next bit. But I know we're starting to come up to time. So, we'll see. We might get a little bit cut short. But yeah. Feel free to make a start on the sixth section.

So, I've already got a database. I did this obviously beforehand. I have no idea if those are my numbers. I'm just going to steal from here. There we go. So, all this is doing is it's just saying, hey, for that database we just created, we want to bind that database to our region worker or RSC worker and make it available. And we're going to make it available on DB. So, it's going to be available on env.db. We're saying, hey, use this database and here's a folder of migrations I want you to run. So, we grab this. I'm just going to sneak ahead again. Migrations. And paste that in. So, we just have a pretty standard SQL to create our table. We're moving away from to dos, we're going into notes now, just so we don't have a collision with our components or whatever. So, exactly the same idea. So, we can run these migrations. I'm going to run them coming out of here into where we had six. And run this locally. I guess. Run this remotely. You already have somebody. Yep. Cool. And then we can insert some dummy data in here. Nice. I'm going to do that remotely as well. Nice. And you remember I said that we have the database being made available to us on DB. What we're going to do is let TypeScript know that. We're going to create a types.ts. And pop that there. And then we're going to use that to create a table. I'm going to pop that there. And then we're going to use that in a new component, a new server component. Which is going to interact with our database. So, we're going to call this notes.tsx. Pop that in here.

20. Using the Environment and Database

Short description:

We can pass the environment to the server component, which allows us to interact with the database. We can use either a React context or async local storage to pass objects to child execution handlers. In the region worker, we bind the worker to the database and pass the environment to the rendering function. The SSR worker has no knowledge of the database, and all the database handling is done by the RSC worker. This setup allows us to use server data that is inaccessible to the client. Server actions, which were not covered in this section, can also be easily implemented by passing the necessary information from the global worker to the region worker. This allows us to update the database based on user actions. If you have any questions, feel free to ask. Lastly, if you're interested in D1, our serverless database, congratulations on creating your first one. It's a lightweight SQLite database that's great for small projects.

So, like I say, server component. It's going to use our environment type. Like I say, it's available on env.db. We're going to prepare a statement, which is going to be querying our database. This is just the API for D1. If you're using Prisma or Drizzle, it's going to be different. But the idea is that we're making some very much server side primitive available within our React app. We're going to grab this data, just like we've done in a fetch, except we're interacting with our database instead. Turn that into some JSX for us. And then we just need to make sure that we've plumbed our environment all the way through down to the server component that needs it. So, another option here would be to use either a React context. You could say at the top of your server component, the shell of your app, in app.tsx, you can create a React context and say, hey, this is my platform context. It has all of my platform things in it, and then any child of our app could just use that context whenever it wants. Or you could use something a bit more platformy, which is async local storage. Kind of like started a little bit of a read me on it here in this archive. So, feel free to take a look, but I didn't quite finish it. If you want more information on this, there are better notes by the actual spec people at the bottom of this read me in the main repo. This is basically just React context. It's a way of passing objects to child execution handlers. So, you can just, like, set this right at the top of your handler, and then access it in children. We're just going simple solution at the moment. So, we're just going to plumb it all the way through. So, we're going to accept in our env parameter here to the whole app, and then we're going to pass it in to notes below. So, let's grab all of this. And then we're going to just need to do it in one more place, which is our region worker. And the region worker is the thing you remember we have our Wrangler region. This is saying, hey, Cloudflare, please bind my worker to this database. It's the worker that gets it. And it comes in just after the request. So, this, like I said, was like this is like something of the platform. So, we're saying export, default, fetch. We want to handle HTTP requests. Here's the request that you get, and here's the environment that you've set up for this worker. So, it's got the database on it, and we just give it to our rendering function. So, we say, hey, when you render app, give it env. And I think that's it. Yeah, that's it. So, now if we do npm run dev, this should spin up a local version of my database, and it should, it should work remotely too when we get there. But yes, sure enough, here is my whole app. We can actually, I should have maybe started with the more boring RSC version. But here's what the region worker is returning to the SSR worker. So, the SSR worker has no knowledge about the database. All it sees is this, hey, please render me like an H3 with this information in it. All of the database stuff is being handled by the RSC worker. And then it all comes together when you server side render the app and then client hydrate. So, you're still able to click all your buttons and you're able to use server data that is very much fundamentally, like totally unattainable in the client. So, before we were seeing, like, hey, the client is still making requests to do whatever, this would be completely impossible now because there's just no way for this client to interact with that database. It's not exposed on the Internet or anything. So, this is really the furthest, like, proof that you can get for, like, data loading. The other thing you can do, of course, is server actions. And that's what originally this section was going to be. I'm sorry if you were looking forward to that specifically. But I had to cut it in the interest of time. But it's really remarkably easy, actually, to get server actions working. We kind of laid the groundwork for it a bit in where was it? Global worker, I think. Yeah. So, we're already looking for this header that React sends when you send off mutation. And so, all you need to do is basically just plumb this through to region worker. I'll show you an example of where this is if you want to take this further and see it all the way through yourselves. But yeah. That would obviously prove the other side. So, you've got data loading with what we have now with this database and stuff. But you could also create a form on your app, submit it, and then React can handle it all the way through into updating the database as well. Any questions on this section? I think... yeah, only thing I got to really say is if you're interested in D1, this is our serverless database. You made your first one. So, congrats. But it's a pretty cool, lightweight SQLite database. Very cool to play around with for small projects and stuff. Yeah.

21. Smart Placement and Next Steps

Short description:

Smart placement is a different way of running workers, allowing them to run close to the origin for better performance. It moves the compute piece to the region where it makes sense, reducing the back-and-forth communication with the database. This architecture model is particularly interesting with React server components, as it allows for a split in the app architecture. The final step is to add a one-liner to the Wrangler toml file for automatic movement. Server actions, bundle optimizations, async local storage, and durable objects are other topics worth exploring. The flight ESM fixture in the React repo provides an example of server actions. Fill out the feedback form for further communication.

Cool. No questions. We'll move right on. So, the last section is mercifully the shortest. And this is just about smart placement. Smart placement is a different way of running your workers. So, before let me bring it back up. Before, workers were running in each and every one of these locations and it would be wherever user is connecting, whatever datacenter is closest to them, that's where the work is gonna run. But smart placement is about saying, no, I don't want it to run everywhere. I want it to run close to my origin because I am interacting with some third party API or whatever and they're only running in one region or have a database somewhere.

And so, in our case, our region worker is now speaking to a database. And this database is not read replicated anywhere. It's only got a single primary. And so, if we were to access it from all over the world, let's say we were wanting to do our server side rendering here and our RRC, if we had a noisy connection with our database, like mine is in Western Europe, I'd have to go back and forth and back and forth in order to render my page. And this is obviously not ideal. It could lead to a much slower application than needs to be. So, smart placement basically says, hey, when you identify that you're having a noisy conversation, just move this piece of compute to wherever it makes sense for it to go. And so, it's gonna say, hey, you're having a lot of conversations in Europe. We're just gonna move this piece over here. And now when a visitor from America comes in, they request the page, goes off to the RSC worker, this can have a noisy conversation with the database really quickly because it's nearby. And then, finally, that serialized DOM just gets back to SSR and this thing finishes off rendering the page. So, it's just a different architecture model. And I hope you see why I think it's so interesting with React server components when naturally you have this split in your app architecture. It makes sense, I think, to run one part of that close to your backend and then the other part everywhere. So, obviously, this one is just running here in America because I'm here. But if I was over here, it would also be running here. Or if I was here. So, like, it's running everywhere. But this piece is running just by your database. Does that make sense? Silence is golden. Cool. Excellent. So, the final step, I think, is literally like a one liner. You add this piece to your Wrangler toml and that's it. It's just automatically moved for you. It can take a second for it to actually move. We do it off of traffic patterns and stuff. So, you might not see it straight away. There's more information about smart placement here. In our docs. So, you're able to, like, get more information about where it's running. You can query it and say have you moved yet? And some information about the analytics as to why we made that choice. But, yeah, I think, my goodness, I think that's the whole thing. Let me think if there's anything else. Like I say, server actions is probably the thing I would go to next. So, let's go back to this readme. I did leave at the bottom here a few topics that I think if you enjoyed this, you would also be interested in. Server actions is top of the list. Next up are just, like, optimizations around how you're producing these bundles for these various different places. So, Ryan and I were just lumping everything together with ESBuild, but you can split them out and only load the components that are relevant for the requests that's coming in. If you're requesting the homepage, you only load the components that are on the homepage. That sort of thing. Async local storage I mentioned. This is just been somewhat recently adopted into winter CG, which is the working group for a lot of these edge run times, like workers. It's a pretty cool API that's available in a lot of places now. If you liked D1, you might like durable objects. It's just another data primitive that we have. And then, a lot of this workshop was stolen from the React repo directly. They have this excellent fixture in here called flight ESM. Flight is what they call React components internally. If you have a look at this, it has the example of server actions. I recommend you check that out. It's obviously not Cloud Flurry. It's very much built into just, like, browsers and it's the React blessed way, if you want to take a look. It's not supposed to be used in production. Neither is mine. But it's just the exploration into these new APIs and stuff. Last thing I will leave you with is my, where has it gone? Ah, it's here. I have a feedback form. Please do fill it in.

22. Final Remarks and Smart Placement Metrics

Short description:

This is my first workshop and I would love to do more and get better at them. I would appreciate any time that you give to filling that out. All the questions are optional. Even if it's the first one, drop off. Please do submit it. The smart placement metrics consider the number of outbound requests for an inbound request. If you have just a one-off conversation with a database, it's not worth moving. But if you have two or more, it's likely worth moving. We sample 1% of requests globally and choose the one with the smallest latency. Thank you all for coming and please fill in the feedback form at Bit.ly RSC workshop.

This is my first workshop and I would love to do more and get better at them. I would appreciate any time that you give to filling that out. All the questions are optional. Even if it's the first one, drop off. Please do submit it.

I think that's it. We have one final question. What are the metrics to count for the smart placement? So, the way that it works is we look at, hey, you've got some inbound request and then how many outbound requests do you then have for that request? So, if you have just a one off conversation with a database, then it's not worth moving, because that could be happening anywhere in the world. But if you're having two or more, then we realize that it's probably worth moving. And the way that we do it is we sample 1% or whatever around in various places around the globe and we just time it, basically. And so, the one with the smallest latency wins, because it's probably close to its back end. And like I say, there are more, like, analytics you can see about the number of subrequests it's making or whatever, I don't know what all this stuff is, but you get to see more information about, yeah, there you go, 1% are being routed. You get to see exactly why we're making those decisions to move it. But, yes, I hope you enjoyed, had fun, learned something. Thank you all very much for coming. I certainly had fun. Please fill in my thing. Bit.ly RSC workshop.