In Web Development, one of the core decisions developers have to make is to decide where to implement rendering in their application. The two most common rendering techniques are

  • Client-Side Rendering: renders web page on the browser
  • Server-Side Rendering: renders web page on the server

Let's understand both the techniques in detail.

Server Side Rendering VS Client Side Rendering:

Before understanding both the techniques, let's get familiar with the following two important Performance Metrics:

  • First Contentful Paint (FCP):
    This metric measures the time from when the page starts loading to the time when any part of the page's content is rendered on the screen. The "content" here refers to text, images, SVG elements. To provide a better user experience, FCP should occur within 1 second of the page starting to load.
  • Time to Interactive (TTI):
    This metric measures the time from when the page starts loading to the time when it is rendered and ready for the user to interact.

Server-Side Rendering (SSR) is a conventional way of rendering. In SSR once the server receives the request for a web page from the browser. The server then compiles and prepares HTML by fetching some user-specific information and sends it to the browser.The HTML and CSS sent by the server are displayed on the browser thereby improving FCP. The browser then takes over, downloads, and executes JavaScript and making pages ready for the user to be interactive. Thus TTI is reduced, thereby improving performance.

While, in Client-Side Rendering (CSR), the application (commonly known as Single Page Application) runs solely in the user's browser. The user sends a request to a website (via browser). The server/CDN delivers static HTML, CSS, and other files. The browser receives these files, parses them, then downloads JavaScript. This JavaScript is being executed, calls to the APIs are being made to fetch dynamic content by the browser while the user only sees loading placeholders at this moment, thereby decreasing FCP. After the server sends the response, the browser displays it thereby making the page interactive.

In short, SSR vs CSR can be summarized as

SSR

  • Server prepares the HTML and sends to the browser for further rendering display
  • Downloads HTML makes the site visible (First Contentful Paint)
  • Download scripts
  • Parse scripts
  • Run scripts
  • Fetch data
  • Ready for users to interact (Time To Interactive)

CSR

  • Download scripts
  • Parse scripts
  • Run scripts
  • Fetch data (optional, but common)
  • Render the content (First Contentful Paint)
  • Ready for users to interact (Time To Interactive)

A simple implementation of Server Side Rendering:

To understand how to implement SSR in React, we'll render a simple app with the basic setup needed.

Start with initializing the app

npx create-react-app ssr-demo

We need a server to return the server-rendered page as a response. Install express as

yarn add express

Next, we create a folder server in the root, with server.js file in it.

In brief, when a request for our page is received by our server, the server renders our App component into a string using renderToString(element). We then update the content of the root element of ./build/index.html file with the markup of the App component rendered as a string and send this as a response to the browser.

At client-side, we call hydrate() instead of render() in index.js. Hydration is the process of putting functionality back into the HTML page that was rendered using server-side rendering. For the first time when page loads it is not blank and crawlers can index it for SEO(another use case of SSR). So hydrate adds the JavaScript to your page or a node to which SSR is applied so that the page responds to the events performed by the user.

Also, as our server is in Node, for it to understand JSX, ES modules we add the following packages,

yarn add @babel/register @babel/preset-env @babel/preset-react

and we create an entry point using index.js in the server folder require these packages and ./server.js

Then, we build the application using

yarn build

update the start script to start the application in package.json

...
"scripts" : {
  ...,
  "start" : "node server/index.js"

}

We can confirm our response is server-side rendered from the Networks tab and checking its preview.

Advantages:

To compare performance between Client-Side rendered application and Server-Side rendered application, we've got a similar application rendered on the client-side.

The client-side rendered application's response preview in the Networks tab is shown below

We compare performance by generating the Lighthouse report on deployed links for both the application.

For Client-Side Rendered application,

For Server-Side Rendered application

We discovered that the SSR app takes lesser time to show anything to the user while the page being loaded i.e improved FCP. As a result, this also reduces the time taken by the user to start interacting with the application i.e. faster TTI, as compared to the CSR app. Another advantage of SSR rendered application is Search engine optimization. The crawlers don't need to wait for the app to bootstrap. The page is already returned as rendered by the server with its unique metadata and helps crawlers to apply SEO algorithms to it.

SSR may get complex as your app gets complex. Implementing SSR has performance benefits as mentioned above but it depends on the scale of its accessibility to the users. SSR’s quick first loads and better SEO performance can be combined with a near-native feeling of CSR. Frameworks that work on this hybrid approach are Next.js or Gatsby

Thank you.

References: