With React Server Components and React’s new suspense SSR capabilities, we get an paradigm shift in the world of client/server side rendering. The pendulum that started in plain HTML pages, quickly swinged to all-client-rendering, is now returning to the server side. Emerging frameworks like Next.js and Remix usher a new era of web development, one where SSR is a first class citizen. In this talk we deep dive into those React features, talk about the state of the art practices regarding server rendering, and maybe get a glimpse into the exciting future of front-back-full-stack relationships.
Dear Client, I'm Leaving You
AI Generated Video Summary
Liad Yosef discusses the importance and evolution of server-side rendering, highlighting its benefits such as improved performance and SEO. He explores different rendering strategies and the challenges of hydration in React. He introduces SuspenseSSL in React 18 as a solution for fetching data in advance and selectively hydrating components. He also mentions React Server Component as a game changer for reducing bundle size in rendering with React.
1. Introduction to Server-Side Rendering
In this part, Liad Yosef introduces himself and the topic of the talk, which is server-side rendering. He mentions the importance of discussing this topic and refers to a quote by Abraham Lincoln. He also mentions that the talk will focus on server-side rendering in React.
Hi. Hi, everyone. Thank you for attending my talk. I'm Liad Yosef. My talk is called Dear Client, I'm Leaving You. We're going to talk a little bit about server-side rendering, server-side rendering, and everything in between.
So I'm Liad Yosef. I'm the lead front-end architect in Douda. I'm a web enthusiast, and in my free time, I'm also an analog astronaut. I have the privilege of going to analog missions around the world, I really like space. So with this in mind, we will turn our talk into somewhat of a dark mode talk, and it will be a space theme.
So you might ask yourself, why do we need to talk about server-side rendering? Abraham Lincoln once said that if I had eight hours to chop down a tree, I'd spend six sharpening my axe, and Rick Sanchez added that the universe is much more complicated than you think. So be prepared for a 20-minute adventure on the rabbit hole of server-side rendering, and how do we approach it in React?
2. Understanding Server-Side Rendering
In this part, Liad Yosef discusses the concept of server-side rendering and its evolution over time. He explains the difference between classic server rendering, client-server rendering, and new server-side rendering. Liad highlights the reasons for using server-side rendering, such as improved performance, better SEO, and addressing issues with client-side rendering. He also mentions the importance of considering performance criteria like cumulative layout shift and large contentful paint. Additionally, he references a talk by Rich Harris on the impact of single-page applications on the web.
It's not like we're watching Dan Abramov on Netflix. So I'll frame my talk a little bit like Netflix. There are a lot of topics to discuss. You can either choose performance or hooks or money heist, a web three or a grid game, but I will focus about server walls.
3. Understanding Rendering Strategies and Spectrum
There's a debate about single-page applications versus multipage applications. Rendering involves who builds the markup, how it becomes interactive, when it's built, and where it's served from. Static rendering provides the same page for everyone, easily cached but not personalized. Client-side rendering allows for personalization but can't be cached and has slow first loads. Incremental static regeneration generates some pages on demand. Real-time server-side rendering is used for personal content. React level components are suitable for web apps with static and dynamic parts. Classic static rendering relies on the cache for serving pages. Incremental static rendering generates variations in the cache. The server is still required, and caching can be triggered by the cache itself.
There's a really good talk by Rich Harris called, Single Page Application Ruined the Web, and generally there's a really good talk in the Twitter sphere, or in the web, about Single Page Application versus Multipage Application, where some people say that multipage applications fall short because they don't give the experience that we want, and other people say that single-page applications, because they load really slow, don't give the performance that we want. That's an ongoing debate.
So, when we talk about SSL strategies, or the multiverse of madness, we need to remember that when we speak about static rendering, we no longer talk about only the client and the server. We need to put something in between, which is the edge network, or the cache, and then we can discuss about the relations between the client, the edge, and the server. In classic static rendering, which is like we saw, the blog pages, the server generates the page on build time, and it sends the page to the cache, to the edge network, and then it goes out of the picture. We don't need the server anymore. It just generated the page, and that's it. The client asks the cache or the edge for the page, and it gets the page, it gets the blog post, and it's important to understand. It's important to notice that all of the clients will get the same page because they all ask it from the cache. Like we said, the pages are easily cached, and they do not require a server, and they have great performance, but they do need rebuild for every update, and there's a problem with data fetching.
In incremental static rendering, the server builds the page, sends it to the cache to be cached, but it also builds a lot of variations, a lot of other variations in the cache, and when the client asks the cache for a page, they get the page, and another client can ask for another page, and they will get another page, but if a third client asks for a page that does not exist on the cache or in the edge network, then it goes directly to the server. The server generates it in real time and sends it to the cache, caches it, and then the client talks to the cache and gets this page. It is like the best of both worlds, but you do still need a server. It can also be triggered by the cache. You can do an invalidation time. For example, if you have a page that needs to be revalidated or refreshed every couple of minutes, then when the client asks the cache for the page, the cache can say this is the page that you want, and the next client, the cache can say, hey, the page is stale, asking the server to regenerate it, while at the same time serving the stale page to the client, and then the server regenerates a new page, replaces it in the cache, and then the next client will get the updated page, which is pretty nice.
4. Rendering Strategies and Hydration
Incremental static rendering allows for caching and reduces build times for multiple pages, but cannot reflect user-specific data. Full server rendering provides highly personalized content and unique pages without a build process, but has a long response time. Edge rendering combines the benefits of rendering and the edge network, allowing for fast and streamed HTML. Hydration, the process of making the markup interactive, is a challenge as it requires sending all the code to the client and cannot be partially hydrated. React is working on solutions such as suspense and other components.
That can also be triggered from the server. So it can be triggered when the server gets new data, it can say, hey, it's been a few minutes since I updated the cache, it can generate a new page or an updated page, replace it in the cache, and then the next client that will ask it from the cache will get the updated version, which is nice.
So in incremental static rendering, it is easily cached, it's very cache heavy, you still rely on cache, it reduces build times for multiple pages, so if you have thousands of blog posts, you don't have to build all of them in advance, but it does require a server, and it cannot reflect user-specific data, because you don't really go to the server and generate a unique page, and the trips to the server are long.
Full server rendering, that's something that's what we call server-side rendering, we have to remember that the cache is no longer in the equation, the client speaks directly to the server, so the client can ask a highly personalized page, for example, account details, my account or my listings, and the server will build it, and it will send to the client something that's very unique to that client. And if another client will ask the server for the page, the server will build something else completely, because that's a different client, a different customer, and they will send it to them.
So, in full server rendering, we get a very highly personalized content and unique pages, and we don't need a build process, which is important, but it does require a server, and we still have the long response time from the server. Why the long response time? Because if we look at the server code, for example, we can see that the line that is relevant here is a render to string, and this line is synchronous, so we need to render everything before we can send the page, and that's a problem. And we will discuss some ways to solve it soon.
And there are voices that say that if your server-side rendering takes more than 200 milliseconds, maybe it's better to do client-side rendering instead.
And now the new thing that everyone is talking about is edge rendering or using the edge network in order to render, and that's like having the best of both worlds, because if we have the edge network that is being spread around the globe, we can use it to render the pages. We don't have to do drifts to the server. So if we just join the rendering and the edge network, we can have something like this. We can have the edge around the world, the client asks for a person-like page from the edge network. The edge network builds it and returns it in real time. But since the edge, it's like a CDN, so it's spread all across the globe, you get the edge point that is closest to the client, which makes it fast. So edge rendering will allow streaming, because now that you have fast times and short times between the edge and the client, you can stream HTML to the client so the client can see parts of the HTML as they are being rendered. It does require an edge network and Next supports it, Remix is going to support it, Netlify has Netlify edge functions, which is pretty awesome. So that's something that you want to take a look at.
5. Using SuspenseSSL for Server-Side Rendering
So a short primer about suspense. If we want to render something lazily, like here, we want to render mouse only if Elon Musk is present. We wrap it in suspense and then we get a nice spinner if you want. And only when Elon Musk arrives, we can render mouse. So this is the idea of suspense.
So if you want to build a website of mentorship to the Avengers and you call it mentor and for example, everyone can select a mentor of their choosing, and you have the mentor page, which is that you have the image and the reviews on the mentor and the name of the mentor, right? So you build it in React. It's pretty simple. You have the name, the image, the description, and the reviews. And let's say that you want—so if the server renders it, it's really simple. So the server just renders it into markup, sending it to the client, and then React does its magic in the client and it becomes interactive and that's amazing. But let's say that you want the mentor image and the mentor reviews to be lazily loaded. Maybe it takes a lot of time to pull the reviews from the third-party data source. So you want to wrap it, let's say, in suspense, right? You would wrap it in suspense with a fallback. But then you have a problem with the SSL, because React will render it in the server, but it doesn't know what to do with the suspense part. It doesn't know, because it's not there, so it will send it to the client, but React in the client doesn't really know what to do. So that's a problem, because you have to fetch everything in advance. And this is the part where SSL is becoming hard. That's why we didn't really utilize SSL in large scale until a few years ago, because it's hard. But SuspenseSSL comes to our rescue in React 18. React introduced streaming HTML, the ability to stream HTML to the client, and SelectiveHydration, the ability to hydrate selectively parts of the clients. So instead of using render to string in the server and hydrate in the client, we can just do rent to pipe of the stream and hydrate root in the client. And then the same suspense code will be rendered in the server with the loading with the spinner and being sent to the client. Then React will hydrate whatever it can in the client. And only when the reviews will be ready, the server will push to the client some sort of a script that said, hey, the reviews are ready. Just replace them in the markup, which is pretty amazing.
6. React Server Component and Bundle Reduction
React Server Component is a game changer for rendering with React. It allows you to define parts of a page as server components, which can go to the database and bundle dependencies without being shipped to the client. By defining only the interactive part as a client component, the bundle size can be reduced by 90%. Check out Dana Bramov's talk and the server component RFC for more information.
And it also knows to do SelectiveHydration. So if several parts of the page are being hydrated and the user clicks on one of them, then React automatically prioritize this part to be hydrated and they know to replay the clicks on this part, which is pretty awesome. React Server Component is also a game changer. It basically means, I won't dive into it because there was another talk on that, but it basically means that if you have a page, that most of the page is statically rendered, you don't need a lot of interaction code, you don't need React, but you want to render it with React. Let's, for example, just the mentor rating is something that you want to be interactive. Then you can just define some part of the page as server components, and those parts can go to the database and they can bundle a lot of dependencies, but none of them will be shipped to the client. So if you just define parts as server components and only your interactive part you define as client component, then only this client component will be bundled and sent to the browser and that can reduce bundle in 90%, which is pretty amazing. There's a good talk of Dana Bramov on that, I recommend you to read server component RFC, it's very informative.