Brendan
Michaelsen
Here at Lithios, we use React for quite a few of our clients’ projects. Our clients and their users love the speed and versatility of the single page application experience, and the base React library provides a robust set of tools to build anything we need. Recently, we’ve taken a deep dive into the structure of our React projects to optimize our builds for each unique client project. One of the most important tools we’ve added to our standard toolbelt through this process is server-side rendering with React. This is especially powerful for marketing pages, public-facing dynamic applications, and SEO-heavy apps - any app where loading speed and SEO are crucial to the client’s business case. In this post, we will explore the difference between server-side rendering and client-side rendering in React, and go through the benefits of the server-side approach.
First off, let’s start with a few definitions. The standard setup for a React application (or indeed any Single Page Application) is Client-Side Rendered, or CSR. Essentially, this means that when someone loads the application, the server responds with a blank HTML page and a script file. When this script file is downloaded and executed, it renders the React application directly in the browser, ready for the user to interact with. This rendering process usually happens quickly enough that it isn’t noticeable to users, but users on slower internet connections may see a slight “flicker” as the page renders from the blank state.
On the whole, this client rendering process is what allows single page applications to be so powerful. Instead of having to request new HTML content on each page load, the React script handles each page change directly in the browser, making navigation and state changes much faster than traditional web applications.
So, how is Server-Side Rendering different? Instead of the server responding with only a blank HTML page on the first load, the server responds with a fully rendered version of the page, along with the same React script file. Then, all the browser needs to do is download and execute the script file as before to enable the same single page application benefits. As you can tell, the SSR method requires React code to be shared between the client side of the application and the server side. The server needs to be set up with all the tools necessary to do a complete initial render before the browser takes over, and this adds complexity to any web application project. However, as we’ll explore in the next section, there are quite a few benefits to this approach.
If only you knew the power of the Server Side...
So, how does the difference between the server returning a blank HTML document and a fully rendered HTML document on the first load benefit your users’ experience?
As we mentioned before, React apps that only use CSR return a blank HTML document from the server before beginning to render the React application. Because of this, the amount of time needed before the user can see the application is the amount of time it takes to contact the server, download the React scripts, and render the React app. Server-side rendering reduces the amount of time before the user can see the application by quite a bit. Instead of having to wait for the downloading and rendering process, the application is immediately visible to the user once the server is contacted. It still takes a few milliseconds for the client React to enable interaction on the SSR content, but the experience is much improved for the end user.
Another downside of the long initial load for a CSR application is that there can be a “flicker” sometimes noticeable by users as the blank HTML page is replaced by the Virtual DOM. This is also fixed by the SSR approach.
Even if the initial rendering process of a CSR application is fast enough to not be noticed by users, it does present a challenge for web crawlers. These crawlers are used by search engines to discover content and make it available to the public. Typically, they are programmed to retrieve the server response for a given website, scan it for content, and index that content for searching. This can present a problem for CSR applications, as the only thing the server returns is a blank HTML page. By using a SSR approach, web crawlers can get the full content from each page of your app.
Let’s say you have an existing React application and you want to add server-side rendering to the first page load. This can be a project that was created with Create React App, a custom webpack implementation or something else. All of the logic required to render your React application is currently contained in the frontend part of the app, probably in an index.js or App.js file. In order to set up server-side rendering, we will need to take a few steps to share React components between our frontend bundle and our server.
The job of a server for this project is to pre-render our full React page before sending it and the associated JS script down to the browser. Create React App already comes pre-packaged with a basic virtual server to host the React app, but we will need something more customizable. At Lithios, we use Express.js. Set up a wildcard route to catch all incoming requests. We will use this to render the React and respond with the bundle for the requested route.
The next step is to determine which route the client is requesting, and respond accordingly. This includes checking if the requested URL should result in an error, like a 404. If your application uses React Router to handle routing, they have a great guide on the adjustments that need to be made to use React Router for SSR.
If the page you are loading is a dynamic page with data pulled from a database, you’ll need to fetch this data before beginning the rendering process. This ensures that the data is available for React to render it into the HTML content.
The goal of optimizing the first load of a React application with SSR is to present the full app to the user as quickly as possible. In a CSR app, the styles are bundled along with the JavaScript and applied to the React components as they are rendered in the Virtual DOM. SSR uses the real DOM, so we need a real stylesheet (e.g. actual CSS) to display the styles correctly on load. This boils down to extracting the rendered CSS from each React component to be displayed and injecting style tag to the rendering HTML before it is passed to the client. If your application uses styled-components, they have a great guide on the procedure to extract a stylesheet during the rendering process.
One of the most important reasons to SSR your first page load in a React application is to improve the search engine optimization, or SEO, of your app. This is especially important when you are rendering dynamic pages. To take full advantage of the SSR benefits, you need to build and inject the appropriate meta tags into the HTML before it is sent to the client. If your application uses Helmet, you can set up an asynchronous provider to automatically pull out meta tags that you can add to the HTML content directly.
The final step in the process of adding SSR to your app is letting the client side know that the first render has already been done for it, and that all the browser needs to do is attach the proper listeners for the user to interact with. This is called hydration, and it replaces the ReactDOM.render function with a ReactDOM.hydrate function. This process saves the client a lot of work on the first load, and reduces loading time for the user.
Experimenting with adding server side rendering to your React application is a great way to speed up your application load times, boost your search performance, and improve your users’ experience. There are also several great off-the-shelf frameworks for setting up an SSR React application. Next.js, Remix, and Gatsby are all great options.
Here at Lithios, we consult closely with our clients to select the right technical stack and tools for their product during our Discovery process, including whether an app should be equipped with server-side rendering out of the box. Ultimately, we use these tools to make our applications fast, reliable, and scalable to help our clients boost their search rankings, increase clickthrough rate, and support future growth. If you have any questions about our process or want to get in touch, drop us a line here.
Contact us to see why the brightest companies trust Lithios.
Get in touch