← Blog

Poor man's server-side rendering

May 01, 2019

Frameworks like Next.js have enabled web developers to easily set up server-side rendered applications. That is, of course, when you’re starting from scratch. But what about all the existing JavaScript applications that are still rendered on the client? How can they enjoy the benefits of isomorphic apps without having to refactor everything, while still being able to use your favourite router?

You can go one of two routes (get it? routes?):


Unless you’re building a web app for the first time, you’re probably familiar with one or two bundlers. With some extra configuration, you can update your build process to generate static HTML and CSS (in the case of apps that use CSS-in-JS), which is served, while the browser loads the JavaScript of your app in the background, a process called hydration.


Although there are plenty of alternatives at this point, you’re probably using Webpack. Your best option, in this case, is probably prerender-loader, a Webpack plugin. It relatively painless to set up, but you might have a hard time setting it up for multiple routes.


If you’re using Parcel, you’re in luck. This guide can walk you through how to set up SSR. Yes, you will have to go through some boilerplate (which is ironically, exactly what Parcel is supposed to help you avoid), but your existing code shouldn’t see many changes. However, you can still use React Router, along with routing animations, styled-components, etc.


I personally don’t like either of these approaches, partly because of the boilerplate, but mostly because there is a better option - prerendering.


Uses Headless Chrome to crawl all the routes of your app and generates static HTML for each of them. It works with create-react-app, Preact and Vue. There’s close to no configuration and the authors have even provided a chart comparing it to similar solutions. Apart from the caveats mentioned in the Readme you should be aware that if you’re using some type of CI or Docker you’ll likely have to set up Pupeteer so the postbuild script that executed during deployment will be successful.


This service is paid for apps with more than 25 pages. The set-up consist of installing a package and adding a line of code to your server (there’s support for all the popular backend frameworks). It’s open-source and recommended by Google. Note that the middleware is only used when a web crawler is visiting your app. Users won’t see a benefit from this (apart from finding your app more easily due to the improved SEO). Which is why i recommend react-snap, because of the added performance boost. If you want to use prerender.io, but want to avoid the monthly fees you can run it in your own server. Here’s a docker image to get you started.


A middleware that prerenders your PWA via Headless Chrome to bots that don’t execute JavaScript. It’s only available for Express.js, Firebase and ASP.net core. When you combine that with its narrow use case, you’ll probably be better off with the alternatives above, but it’s worth a look.


Whichever method you chose, you’ll benefit from better SEO of your app and your users will experience faster loading speeds. So if you haven’t already, consider investing some time to make your app isomorphic.

Sai Krishna

Written by Boris Yordanov.

Psst! Wanna hire me?

Here's my resume