Server-side rendering with React

What is server-side rendering? How to do this with React?

Server-side rendering, is also calledsolid state relay, Is the function of the JavaScript application rendered in the server rather than in the browser.

Why do we do this?

  • It makes your website have a faster homepage loading time, which is the key to a good user experience
  • This is essential for SEO: search engines cannot (yet?) efficiently and correctly index applications that are dedicated to the client. Although Google has made the latest improvements to indexing, there are other search engines, and Google is not perfect anyway. In addition, Google prefers websites with short loading times, and having to load the client is not conducive to improving speed
  • It’s great when people share your website pages on social media because they can easily collect the metadata (images, titles, descriptions...) needed to share links well.

If there is no server-side rendering, all your servers will be an HTML page with no body and only some script tags, and then the browser will use these script tags to render the application.

Client-side rendered applications are ideal for any subsequent user interactions after the first page is loaded. Server-side rendering allows us to gain an advantage in the middle of the application rendered on the client side and the application rendered on the back-end: the page is generated on the server side, but all interactions with the page after it is loaded are processed on the client side.

However, server-side rendering also has its disadvantages:

  • It can be said that a simple SSR proof of concept is simple, but the complexity of SSR will increase with the complexity of the application
  • Rendering large applications on the server side may take up a lot of resources, and under heavy load, it may even provide a slower experience compared to client-side rendering because you have only one bottleneck

A very simple example for server-side rendering of React applications

SSR settings can become very, very complicated, and most tutorials will introduceRedux,Reaction routerAnd many other concepts from the beginning.

In order to understand the working principle of SSR, let us start with the basic knowledge to implement proof of concept.

If you only want to study the library that provides SSR without disturbing the basic work, please skip this section

To implement basic SSR, we will use Express.

If you are not familiar with Express, or need some help, please check my free Express Handbook here:

Warning: The complexity of SSR will increase with the complexity of the application. This is the minimum requirement for rendering basic React applications. For more complex requirements, you may need to do more work, or also check React's SSR library.

I assume you started a React application using the following methodcreate-react-app. If you are just trying, use install nownpx create-react-app ssr.

Use the terminal to go to the main application folder and run:

npm install express

There is a set of folders in your application directory. Create a new folder namedserver, Then enter it and create a file calledserver.js.

Followingcreate-react-appBy convention, the application is located atsrc/App.jsfile. We will load the component and useReactDOMServer.renderToString(),Provided by thereact-dom.

What you get./build/index.htmlFile, then replace<div id="root"></div>Placeholder, it is a label attached by default to the application, with `<div id="root">\${ReactDOMServer.renderToString(<App />)}</div>.

Everything insidebuildExpress will provide the folder as is.

import path from 'path'
import fs from 'fs'

import express from ‘express’ import React from ‘react’ import ReactDOMServer from ‘react-dom/server’

import App from ‘…/src/App’

const PORT = 8080 const app = express()

const router = express.Router()

const serverRenderer = (req, res, next) => { fs.readFile(path.resolve(’./build/index.html’), ‘utf8’, (err, data) => { if (err) { console.error(err) return res.status(500).send(‘An error occurred’) } return res.send( data.replace( ‘<div id=“root”></div>’, &lt;div id="root"&gt;</span><span style="color:#e6db74">${</span><span style="color:#a6e22e">ReactDOMServer</span>.<span style="color:#a6e22e">renderToString</span>(<span style="color:#f92672">&lt;</span><span style="color:#a6e22e">App</span> <span style="color:#f92672">/&gt;</span>)<span style="color:#e6db74">}</span><span style="color:#e6db74">&lt;/div&gt; ) ) }) } router.use(’^/$’, serverRenderer)

router.use( express.static(path.resolve(__dirname, ‘…’, ‘build’), { maxAge: ‘30d’ }) )

// tell the app to use the above rules app.use(router)

// app.use(express.static(’./build’)) app.listen(PORT, () => { console.log(SSR running on port </span><span style="color:#e6db74">${</span><span style="color:#a6e22e">PORT</span><span style="color:#e6db74">}</span><span style="color:#e6db74">) })

Now in the client applicationsrc/index.jsInstead of callingReactDOM.render():

ReactDOM.render(<App />, document.getElementById('root'))

callReactDOM.hydrate()The same, but once React loads, it also has the additional function of attaching event listeners to existing tags:

ReactDOM.hydrate(<App />, document.getElementById('root'))

All Node.js code needs to beTower of Babel, Because the server-side Node.js code does not understand JSX, nor does it understand ES modules (we useincludestatement).

Install the following 4 packages:

npm install @babel/register @babel/preset-env @babel/preset-react ignore-styles

ignore-stylesIs the Babel utility, it will tell it to ignore the use ofimportsyntax.

Let's create an entry point inserver/index.js:


require(’@babel/register’)({ ignore: [/(node_modules)/], presets: [’@babel/preset-env’, ‘@babel/preset-react’] })


Compile the React application to fill the build/ folder:

npm run build

Let's run this:

node server/index.js

I said this is a simple method, it is:

  • When using import, it cannot process the rendered image correctly, and the import requires Webpack to work properly (this makes the whole process very complicated)
  • It does not handle page header metadata, which is very important for SEO and social sharing purposes (among other things)

So while this is a good example of usingReactDOMServer.renderToString()withReactDOM.hydrateTo obtain this basic server-side rendering effect, it is not enough for actual use.

Server-side rendering using the library

SSR is difficult to get right, and React has no practical way to achieve it.

If it is worth the trouble, complication, and overhead to get the benefits, instead of using other technologies to provide these pages, then it is worth discussing.Discussion on RedditThere are many opinions in this regard.

When server-side rendering is important, my advice is to rely on pre-built libraries and tools that keep this goal in mind from the beginning.

I especially recommendNext.jswithGatsby.

Download mine for freeResponse Handbook

More response tutorials: