Server side rendering took a bit of a back seat with the initial popularity boom of client side frameworks. On the other hand, SPAs create a challenge with SEO since many web crawlers aren't capable of crawling client side JS bundles. However, SSR is making a comeback with the ease of implementing our beloved client side frameworks on the server. This gives us some nice advantages while still utilizing the performance power from a client side framework. In the this article I'd like to take a brief look into server side rendering a React App.
There really are two main advantages of server-side rendering
- Better SEO
- Faster initial page loads
With a client-side application, we're only generating a small HTML file with basically zero content outside of a script tag with something like
This makes it pretty difficult for web crawlers to read what kind of content is on our site, killing our SEO. By generating our React components as HTML files on the server, we avoid this problem.
Browsers load HTML, CSS then the JS of our web pages and Apps. If all the content of our SPA written is inside our React components users won't see any content until after our CSS and JS is fully loaded. By handling our JSX content as HTML markup on the server our SPA's initial load time will be much faster. There is a downside to this though, which I'll explain a bit later.
I'm going to make the assumption that you're familiar with setting up an Express server with Node.js as going through that setup is beyond the scope of this article. If you've never setup an Express server before, have a look at this Express example. To get your React SPA from client to server side you'll follow the basic Express app setup. Our server will also need React the
ReactDOMServer object to convert our component to markup. This object comes with a few important methods, one in particular.
renderToString() method accepts a React component and converts it to our HTML markup, allowing crawlers to work their magic. On the client side, our components don't change much in terms of their regular syntax, however instead of
ReactDom.render() we must now use
Reading the initial documentation on hydrate feels slightly more complex than it actually is. When we send an HTML file to the client via server side, we're sending static content along with it. However, we know that with a React app, that many of our components will need to be updated with state changes. Handling these state changes by generating our HTML on the server, sending it to the client, client making a request for an update to the server and then the server sending back the updated HTML is time consuming (why we have client side frameworks in the first place).
We can however, send a static version of our App as an HTML string to the client. This "dehydrated" version will then receive event listeners to any DOM nodes we specify in our react components which can then be referenced for changes in our applications state, similar to any other client-side only React App you may have created in the past.
Setup for React Apps via SSR are quite complex. Webpack configurations need to be set up for JS bundles, like any application from scratch setup, however servers also can't read JSX which requires more configuring. Thankfully, frameworks like Next.js and Gatsby have emerged to make this setup easier.
SSR can help speed up first paint, but time to interactive can cause users to be deceived since only our static content is loaded on the server side, but our bundled JS still needs to load.
Thanks for reading this very brief introduction into how server side rendering works with a React application. As always comments, questions and constructive criticisms are always welcomed.