What is React Server Side Rendering and should I use it?
- Written by
- Name
- Mladen
- Title
- Software Engineer
- Published on
As stated in the title, I will try to present some pros and cons regarding this not-so-hot-anymore technology, and also help someone new to React SSR understand it a bit more.
First of all, let's dive into some terminology stuff
SSR? Isomorphic? Universal? WTF?
First of all, for some of you that don't know (as I haven't until recently) server side rendering is nothing special. Any ordinary static website is server side rendered, a server gets your request and spits out HTML to your browser.
We also had templating languages doing some neat tricks for us that are considered as server side rendering.
BUT when we talk about JavaScript, Server Side Rendering usually points out to an ability of a front-end code to render HTML while running on a back-end system.
SPA + SSR = Isomorphic*
* or universal
Isomorphic or Universal apps are interchangeable phrases commonly referring to a way of writing your apps so that you use the same language on both server and client side. More specifically, for JavaScript, best case scenario would be that you also use the same syntax.
For example if you are running your back-end in NodeJS you are probably using CommonJS module syntax.
//...Our awesome app code... const circle = require('./circle.js'); //...Rest of our awesome app code...
And you write your React in ES6
//...Our awesome app code... import React, { Component } from 'react'; //...Rest of our awesome app code...
Using Webpack we can start using our ES6 import syntax also on server side of our app, and that is the true goal of an isomporphic app.
Why would I want to use React with server side rendering in the first place?
Well, our traditional React app would have this flow when loading:
- Browser requests a page
- PAUSE
- We get pretty empty html and a script tag pointing to a JS file where all of our code lives
- Browser requests that script
- PAUSE
- Content visible on the screen
We now see that we have 2 round-trips to server, which is kinda acceptable. But let's imagine that our app has a list of blog posts, or a series of images, or whatever that we need to request from some API, now the flow is a bit more realistic and looks something like this:
- Browser requests a page
- PAUSE
- Browser requests our JS
- PAUSE
- React app boots, requests data from backend
- PAUSE
- Content visible on the screen
As you can see, the number of requests increased, so there is a lot more happening before our user sees anything on the screen.
Now for the Server Side Rendered React App
- Browser requests a page
- PAUSE
- Content visible on the screen!
Whaaat? How? Let's look at it in a bit more detail
- Browser requests a page
- Server loads React in memory
- Server fetches required data
- Server renders React app
- Server sends generated HTML down to the browser
- USER SEES CONTENT
- Require JS file
- React App boots, requests data from backend
- App rerenders (hydrates) on the screen.
As you can see we did only 1 trip to the server before getting some content for our user. Now, the content that we served before we rerendered everything is static, so if our user is super fast and starts clicking before hydrate happens, the app will not be responsive.
What problems are we solving using this approach?
Two of the biggest ones are SEO and perceived performance boost
If your app is a bit larger, search engine crawlers will see your page as a mostly empty html with a single script
tag that requests your massive React app, as it won't wait for the moment it fills up the DOM, your page won't get indexed.
Meanwhile, Google improved their crawlers to search for javascript created content also, but Bing or Baidu are still lacking this feature, so if larger percentage of your audience is coming from other search engines, you will have to work that out.
With React SSR your First Meaningful Paint time will be (in most cases) significantly lower. This is an important metric for some companies. You certainly heard stories of numerous companies increasing their profit by cutting down on load times for their web apps. (https://wpostats.com/).
Above I wrote perceived performance boost, and while it is true that you will get content to your user faster than using a traditional React app, the catch is that it probably isn't a performance boost. In the SSR request example a little bit above you see that server is also doing everything that client does: It boots up React, renders the app for you and spits out HTML. This means that you are doing everything 2 times which isn't ideal. Also renderToString()
method that react uses to convert your beautiful jsx code to HTML is really slow and also synchronous. This puts server under more load, and your initial response from server will arrive later.
If you decided to go with server side rendering, you will probably have 2 servers: One for the API and business logic, and another one for rendering purposes. Knowing how big of a task your rendering process is, you can scale up your rendering servers to match the increased load.
Since I am not the first one who had issues with these problems, engineers over at Walmart labs created a tool that optimizes those quirks React SSR has, called Electrode. They also wrote couple of cool articles about it, really worth reading if you made it this far :) (https://medium.com/walmartlabs/using-electrode-to-improve-react-server-side-render-performance-by-up-to-70-e43f9494eb8b)
There are also "frameworks" for React SSR like Next.js for example which is gaining nice traction and support from community.
Using React SSR also adds multiple levels of complexity. Remember freely using window
or document
to do stuff? Forget about it!
I am just kidding of course, but you will have to be extra cautious, since the app will run first in a Node environment, window
and document
for example are not defined there, so you will have to restrain yourself from using them outside componentDidMount
or without if (typeof window !== 'undefined')
. I cannot remember how many times my app broke until I got used to it.
Your Node server will catch your routes and pass it down to React to decide what to render, so how does it have access to your router on server? It doesn't. Solution? Double routes. Your Application renders depending on something from your Redux store? Double store.
There are many complexities introduced with SSR, luckily for us, tools like Next.js solve many of them, but if you are stuck with solving all those problems by yourself, it will be really hard.
Should I use React Server Side Rendering?
Maybe.
If you / your company really values SEO, and significant number of your visits come from search engines other than google, yes.
If you / your company really values user perceived performance, think about it, if your client side application performance can't get anything better, then yes.
In any other case, my advice is to stay out of it, it will just increase complexity of your project without really much benefits.