Mastering SSR and CSR in React: Code-Based Rendering Guide

Before implementing Client-Side Rendering (CSR) or Server-Side Rendering (SSR) in a web application, it’s important to understand what these terms mean and how they impact content presentation and performance.

Server-Side Rendering (SSR) 

Server-Side Rendering refers to a method where the server generates the complete HTML for a web page before sending it to the browser. The server handles the logic and builds the structure of the page, delivering a fully rendered HTML document to the user. 

SSR Workflow:

1. The browser sends a request to the server for a specific page.
2.The server fetches the necessary data and inserts it into an HTML template.
3.It then generates and returns the complete HTML with the rendered UI.
4.The browser displays the page immediately—no need to run JavaScript initially.
5.After the initial load, client-side JavaScript may take over for further interactions and updates.

Client-Side Rendering (CSR) 

In Client-Side Rendering, the HTML content and UI are generated directly in the browser using JavaScript. When a user requests a page, the server sends a minimal HTML file, and the client-side JavaScript handles fetching the data and rendering the interface. 

CSR Workflow: 

1.The server delivers a basic HTML file with references to JavaScript and CSS files.
2.The browser loads this HTML and begins downloading the CSS and JavaScript resources.
3.The JavaScript code is executed to fetch data and build the UI components.
4.The complete page, including text, images, buttons, and styles, is rendered in the browser.
5.Interactions such as form submissions and button clicks are handled by JavaScript, which updates the DOM dynamically.

JavaScript Dependency 

  • CSR requires JavaScript to function. If a user’s browser has JavaScript disabled, they may only see a blank or incomplete page. 
  • SSR does not rely on JavaScript for the initial page load, making it more accessible and providing a basic experience even if JavaScript is turned off. 

Now, let’s explore how to implement both CSR and SSR in a React app. The latest version of React offers a built-in template that supports SSR out of the box. 

Below is the code example demonstrating this setup: 

Implementing SSR in React with Vite 

  1. Setup your react project using vite 

npm create vite@latest 

  1. Setup your project name 

? Project name: vite-project //provide your project name 

3. Select the framework 

>Vanilla 

4. Select a variant 

?Select a variant: 

>create-vite-extra //

5. Select a template 

?Select a template: 

>ssr-vanilla 

6. Now you’re given another option to choose the variants, select a variant  

?Select a variant: 

>Javascript 

Now we have successfully set up the react project with Vite. We do not have to create the configuration ourselves, vite provides that for us as well. The codebase contains the preconfigured entry-client.tsx, entry-server.tsx and server.js. 

entry-client.tsx code 

import './index.css' 
import React from 'react' 
import ReactDOM from 'react-dom/client' 
import App from './App' 
ReactDOM.hydrateRoot( 
 document.getElementById('root') as HTMLElement, 
 <React.StrictMode> 
   <App /> 
 </React.StrictMode> 
)  

entry-server.tsx code 

import React from 'react' 
import ReactDOMServer from 'react-dom/server' 
import App from './App' 
export function render() { 
 const html = ReactDOMServer.renderToString( 
   <React.StrictMode> 
     <App /> 
   </React.StrictMode> 
 ) 
 return { html } 
} 

server.js code 

import fs from 'node:fs/promises' 
import express from 'express' 
// Constants 
const isProduction = process.env.NODE_ENV === 'production' 
const port = process.env.PORT || 5173 
const base = process.env.BASE || '/' 
// Cached production assets 
const templateHtml = isProduction 
 ? await fs.readFile('./dist/client/index.html', 'utf-8') 
 : '' 
const ssrManifest = isProduction 
 ? await fs.readFile('./dist/client/.vite/ssr-manifest.json', 'utf-8') 
 : undefined 
// Create http server 
const app = express() 
// Add Vite or respective production middlewares 
let vite 
if (!isProduction) { 
 const { createServer } = await import('vite') 
 vite = await createServer({ 
   server: { middlewareMode: true }, 
   appType: 'custom', 
   base 
 }) 
 app.use(vite.middlewares) 
} else { 
 const compression = (await import('compression')).default 
 const sirv = (await import('sirv')).default 
 app.use(compression()) 
 app.use(base, sirv('./dist/client', { extensions: [] })) 
} 
// Serve HTML 
app.use('*', async (req, res) => { 
 try { 
   const url = req.originalUrl.replace(base, '') 
   let template 
   let render 
   if (!isProduction) { 
     // Always read fresh template in development 
     template = await fs.readFile('./index.html', 'utf-8') 
     template = await vite.transformIndexHtml(url, template) 
     render = (await vite.ssrLoadModule('/src/entry-server.tsx')).render 
   } else { 
     template = templateHtml 
     render = (await import('./dist/server/entry-server.js')).render 
   } 
   const rendered = await render(url, ssrManifest) 
   const html = template 
     .replace(`<!--app-head-->`, rendered.head ?? '') 
     .replace(`<!--app-html-->`, rendered.html ?? '') 
   res.status(200).set({ 'Content-Type': 'text/html' }).send(html) 
 } catch (e) { 
   vite?.ssrFixStacktrace(e) 
   console.log(e.stack) 
  res.status(500).end(e.stack) 
 } 
}) 
// Start http server 
app.listen(port, () => { 
 console.log(`Server started at http://localhost:${port}`) 
}) 

For rendering the react app on the server, we first have to create the build for both the client and server. This is the build script. 

npm run build //creates the build 
npm run build:client //creates the build for client side 
npm run build:server //creates the build for server side 
npm run dev //starts the application 

Conclusion

For React developers, mastering both CSR and SSR is key to building performant and scalable apps. CSR enables rich client-side interactivity, while SSR improves initial load and SEO.  With React’s latest SSR tooling, you can easily implement either—or both—based on your project’s needs.

Reference : https://prismic.io/

Scroll to Top