Server Side Rendering with Create React App

Written by benlu | Published 2017/02/18
Tech Story Tags: react | javascript | server-side-rendering | create-react-app

TLDRvia the TL;DR App

UPDATE: I’ve written a v2 to this, its a bit better reasoned, check it out here: https://medium.com/@benlu/ssr-with-create-react-app-v2-1b8b520681d9

I’ve been using create react app a bunch and wanted to improve performance by adding server side rendering to the apps I was making. This isn’t as straight forward as I initially thought, but to get started, you can view this medium article: https://medium.com/@patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d

This is about server side rendering and redux

Source code is available: https://github.com/ayroblu/ssr-create-react-app

Pretext

In production, create react app is basically just some static files, which is great for basic deploys, but incorporating server side rendering requires a server, and I’ve used nodejs a fair bit so following a bit of https://medium.com/@patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d, you can setup an express + create react app website, and start adding server side rendering.

What I’ve done doesn’t go in to session state modification or service worker, both things I think would be natural progressions, but just haven’t gotten to yet.

Theory

With Server Side Rendering, we want to render some basic pages, I don’t want to mess around with authenticating users or complex conditionals because I usually handle that in the Single Page App (SPA) way on the client side. This pretty much means I want to render raw html and nothing else, leave the html the way it was, but with the react ‘root’ element filled in with the route information

Making Changes

App Setup

For those who aren’t familiar with redux, react-router setup or curious how I’ve done it: I’ve been playing around with different redux styles so currently I’ve got three folders, actions, reducers and types, which looks like:

With a store.js that looks like:

Obviously I stick in middle where where I feel appropriate (redux-saga, logger, devtools…), based on react boilerplate I believe

For your routes, move them in to their own component routes.js which looks like:

Obviously, I’ve also got a components and containers directory too, containers are the main pages, and components are things that have no state and really just serve simple functions, seems to be the way things are progressing

Actual Server Side Rendering now

Okay, so with that boilerplate out of the way, if you’ve followed the linked article with the express server setup, then you’ve got a server/app.js file now. So first, there’s a couple of important imports:

These bring your client side react code in to the nodejs side, (don’t forget to install ignore-styles if you haven’t with npm install/yarn add). We ignore-styles because you import css in create react app and without webpack, we can’t really handle that, so this is a quick cheat. babel-register is apparently a bad idea for production, but, for the most part its fine and you need it because you’ve babel’d your client side code. The rest is pretty self explanatory, you need to create your react elements and turn them in to strings.

Note: because we work at the router level, if you have parent components above that, in this case, redux, but perhaps material-ui or similar, then you’ll need to reconstruct them here (or required file so you can use import etc)

Here’s the code, its not pretty, but it gets the job done:

So quickly going through it, this function goes in an express handler, you first read the file create-react-app has generated (index.html in the build dir). Use react-router’s match method to match the url and given some props, create my react elements as html. Finally replace some text (so go in to your public/index.html and add something to your root element like {{SSR}}, then the data is replaced and finally sent to the user.

And you’re done! Don’t forget bits and pieces here and there like:

app.use('^/$', universalLoader)app.use(express.static(path.resolve(__dirname, '..', 'build')))app.use('/', universalLoader)

For more advanced projects, such as those who’ve ejected and messed around a bit more with their webpack configs, this probably won’t be enough, but if you’re producing some simple websites this is a great way to speed up load times!

Checkout https://github.com/ayroblu/ssr-create-react-app which is the boilerplate code I’m using for this (which means there are favicons and code is a bit more split out). Let me know what you think, definitely want to add service workers to this amongst other things!

Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising & sponsorship opportunities.

To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.

If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!


Published by HackerNoon on 2017/02/18