Client-Side Rendering a React App with Express.js

How to serve a React app using Express.js by implementing client-side rendering solutions

Putra Aryotama
JavaScript in Plain English

--

Photo by Kate Townsend on Unsplash

You have setup and created your react app (using create-react-app, other boilerplates, or even creating it from scratch). Now you’re trying to serve it to the web so the world can see what you’ve made. Sure, for easy deployment and minimal setup you can go for the already established platforms such as Netlify, Heroku, Firebase Hosting, Github Pages, or many others. This article, however, is not about that. This article is about setting up your own server and deploying your site/app using good ol’ Express.js.

Why, you may ask? For learning purposes, of course. Having an understanding of how servers deliver your app/site is beneficial for your programming fundamentals. It may also aid in your future work in deploying (and configuring) your sites.

In this article, I will focus on how client-side rendering works in deploying a react app using Express.js. To gain a better understanding, you should also check out how server-side rendering works as a comparison. That way, you will have a much clear understanding of how each method works and gain a whole view of both client-side and server-side rendering solutions. I have written an article on server-side rendering. So, check it out:

By the end, you should have a clear understanding of what client-side rendering is and how to apply client-side rendering solutions with Express.js. In addition to that, you should also gain a clear understanding of how servers work and how sites/apps are deployed to servers.

The Project

You can use your existing react app if you already have one, or you can start a new one using create-react-app and leaving the main code inside src directory as is (as we’re focusing on the back end). You can also try and start a react app from scratch which can enhance your understanding of the bits and pieces that goes inside a react app.

To learn how a react app is built from scratch, you can follow the link below and read my earlier article:

I will use the code from the article above where the react app is created from scratch. Please note that by following the ‘react app from scratch’ example, you will understand how the JavaScript file in the public folder came to be (which is significant in understanding client-side rendering explained at the end of this article). Your project directory should at least have the following folder structure and files:

react-app/
|--public/
| |--index.html
| |--bundle.js
|--src/
| |--app.js
|--babel.config.js
|--package-lock.json
|--package.json
|--webpack.config.js

This article will assume that you already have a basic understanding of JavaScript, Node.js and React. If not, for basic setup (such as Node and React), I recommend you to follow the link above to start a react-app from scratch.

Express.js

Express.js styles itself as “fast, unopinionated, minimalist web framework”. Express is a go-to JavaScript framework if you’re building a back end for your project. By now you shouldn’t be surprised if JavaScript is used for server-side language.

To install Express.js, run the following command:

npm install express

After installing Express, create a new directory at the root of the project named server.

mkdir server

This directory is where we will setup the Express back end. By now, you should at least have three directories at the root (if you’re following along from ‘creating react app from scratch’ article) called public, src, and server.

Inside the server directory, create a file named index.js:

touch server/index.js

Your server directory should now look like this:

react-app
|-server
| |-index.js
|...

In server/index.js, add the following code:

server/index.js
  1. We require the express module and call the top express function, express(). We also set the desired port number, which in this case is 3000.
  2. We instruct express to start the server and listen to the port that we’ve set. The console will output ‘Server now listening at http://localhost:3000.

To start the server up, enter the following command in the terminal at the root of the project directory:

node server/index.js

When we open http://localhost:3000, there wont’ be any content shown in the browser. Instead, there will only be an error message “Cannot GET /”. This is because we haven’t specified any routes in Express, especially the content to be delivered from the ‘/’ (home) route. We have only required the express module and instruct express to start the server and listen to port 3000 in server/index.js.

Nodemon

Before we make any changes to server/index.js to serve the react content, let us incorporate Nodemon to our application. Nodemon is a tool in developing Node-based application that helps to automatically restart the said application when file changes in the directory are detected. That way, we would not have to manually cancel and restart our express server every time we want to see how the changes we’ve made takes place.

Install Nodemon globally (recommended) by typing the following command:

npm install -g nodemon

You can now use Nodemon on other projects in your machine as it is installed globally in your machine.

Now, instead of using the node command to start our express server let us use nodemon:

nodemon server/index.js

Like the node instruction, the command will start our express server. This time, however, whenever any changes are made and saved in our server/index.js, our server will automatically restart to allow those changes to take place.

Even better, let’s also add an npm script in package.json named serve for starting our express server using nodemon:

package.json

Now, to start up the server, we can just call the following command from the root of the project terminal:

npm run serve

Express().static

To serve our react app, we will use the built-inexpress().static middleware from Express.js. An Express.js application is basically a series of middleware and routing functions. Middleware functions tell Express.js what to do with incoming requests. Whether to transform the request data, sending back response, or passing it to the next middleware. The express().static middleware instructs express to serve static files from a specified directory.

In our server/index.js, add the following code:

server/index.js

3. We use Node’s path module to get the path to our public directory where our bundled react app (in a JavaScript file called bundle.js) and its corresponding html (index.html) is situated. Using the public directory path, we instruct express to statically serve the files in the said directory.

Now, when we go to localhost again, our react app content should be successfully served in the main route (‘/’):

react-app served through localhost

Voila! We have our react-app successfully served through Express.js back end. When directing to the home (‘/’) route, express will search for and serve the first index.html it finds (including all the required files in that html such as JavaScript and css) in the public directory.

Another question arise, what if users enter different routes (like /home, /about, /sdfsadfs, etc.) that are not specifically set in our back end? Users may get the error “Cannot Get”.

To solve this problem, we should instruct Express to redirect all incoming requests to the home (‘/’) route. We do this by adding a bit more code to our server/index.js file:

server/index.js

4. We added another middleware that instructs Express to redirect any route other than the home route (‘/’) back to the home route (‘/’). That way, users won’t be able to enter any random route and get a “Cannot GET” error.

Now, every time users go to our site, our back end will automatically route incoming requests to the ‘/’ (home) route.

Client-Side Rendering

We have successfully served our react app using express.js back end. The way our react app is rendered in this project is through the client side (thus the name ‘client-side rendering’). When requests come to the home route, we instruct express().static to send back the index.html file along with the JavaScript and css files that the html file requires. Our index.html file only contains an empty div element with the id ‘root’ inside the body tag. The actual rendering of the page UI is done by the JavaScript file, bundle.js, where all our react code resides. This is why it is called ‘client-side rendering’, the UI rendering process is done in the client side by the client’s browser after the JavaScript files have been successfully sent to and downloaded by the client browser. This is the opposite of ‘server-side rendering’ (more about this in another article, so stay tune!).

Client-side rendering has its pros and cons. The biggest upside of client-side rendering is its rich and ease of interaction. After the initial load, the UI interactions should be very responsive as all the JavaScript code needed is already there downloaded at the initial load. The downside is, of course, the initial load itself. As the app becomes richer and more complicated, the bigger the size of the files needed to be downloaded will be at the initial load by the browser. This may be bad for user experience.

The biggest downside, though, has to do with search engine optimization (SEO). Because all the contents of our app are served to the client from inside a JavaScript file sent by the server, it may prevent web crawlers to crawl the content of our app. As a consequence, Google search results will take a hit.

Summary

In this article, we have successfully served a react app (built from scratch) using Express.js back end. The UI is rendered through client-side rendering by the client browser after all the required JavaScript (and css) files have been downloaded.

--

--

I write for fun! I write about my field of work (tax, accounting, and economics) and hobby (programming, javascript, react). Sometimes in Indo, usually in Eng