Server-Side rendering (SSR) and React Server Component (RSC)
Date:
1. Introduction
Regarding the latest features of React: Server Components, this article Making Sense of React Server Components by Josh WComeau has done a great job to explain everything. This article simply picks some key points from it, and did an experiment to verify the idea at the Experiment Section below.
2. Server Side Rendering (SSR)
SSR is an umbrella term that comprises several different strategies and implementations, but the most typical version of it looks like this:
User visits our web app.
The request is received by Node.js, which runs React in a windowless server environment. It renders our application and produces a fully-formed HTML document containing all of the initial UI.
When this HTML document loads on the user’s device, React will re-render all of the same components, repeating the work done on the server. Instead of generating new HTML elements, however, it “adopts” the HTML elements that were generated by the server.*This is known as hydration.
There's one big limitation with this model. All of the code we write will be executed on the server and the client. There's no way to create components that render exclusively on the server.
3. React Server Component (RSC)
In the “React Server Components” paradigm, components are Server Components by default. A Server Component runs exclusively on the server. This code will not re-run on the user's device; the code won't even be included in the JavaScript bundle!
This new paradigm also includes Client Components. A Client Component is a component that runs on both the server and client. Every React component you've ever written in “traditional” (pre-RSC) React is a Client Component. It's a new name for an old thing.
As I write this, there's only one way to start using React Server Components, and that's with Next.js 13.4+, using their brand-new re-architected “App Router”.
4. Experiments
4.1 Move heavy library to backend
A proper syntax-highlighting library, with support for all popular programming languages, would be several megabytes, far too large to stick in a JS bundle. As a result, we have to make compromises, trimming out languages and features that aren't mission-critical.
But, suppose we do the syntax highlighting in a Server Component. In that case, none of the library code would actually be included in our JS bundles. As a result, we wouldn't have to make any compromises, we could use all of the bells and whistles.
This is the big idea behind Bright, a modern syntax-highlighting package designed to work with React Server Components.
Comparing the page load bundle size on production mode for these 3:
One-line-code page without any syntax highlighter: 166 kb. Code here.
One-line-code page with react-syntax-highlighter (forced
use client
): 189 kb. Code here.
From the bundle sizes above, we can see that with Bright using React Server Component, it addes trivial size to the bundle. Looking deeper into the loaded JS file of the react-syntax-highlighter version, there is an extra JS file (22kb transferred):
This just includes 10 languages and 1 theme of react-syntax-highlighter. If more are included, the bundle size could be much more.
Note: for react-syntax-highlighter, if we remove the
use client;
directive, it can also run on the server side, making the bundle size smaller. We force it to be loaded on client side for comparison purpose. For bright though, it allows only loaded on the server (server only
).
4.2 Faster LCP
There are multiple metrics to evaluate how fast users (perceive to) access your website. Among them, First Contentful Paint (FCP) and Largest Contentful Paint (LCP) are important ones. I examines these loading metrics for my personal portofolio site https://jses.io, which static content.
Server Side Rendering (SSR) and React Component Server (RCS) would be helpful to improve LCP, because initial HTML markup will be returned to display once users access the page. For the case of jses.io, all content is static, so they could be rendered on the server, and sent to browser to display quickly. Let's see how much it can improve.
I used PageSpeed Insights to check the metrics.
Firstly, I enforce most content of the page to be loaded by front-end, it's nearly Client-Side Rendering (CSR) for the whole page. The PageSpeed result is like:
Once the SSR and RCS are enabled, the overall performance rate was increased to 75 to 92. Check the PageSpeed result below.
There is a hugh improvement in terms of loading performance:
Largest Contentful Paint (LCP): 1.3 s -> 0.4 s
Total Blocking Time (TBT): 450 ms -> 230 ms
Speed Index: 1.3 s -> 0.6 s
The improvement boost the loading time by almost 100%.