DEV Community

bricoo
bricoo

Posted on

Deploy create-react-app with react-router on Heroku

Most beginner personal web development projects start with using create-react-app. create-react-app is a simple react-based application, prominently used by newcomers as a tutorial. However, it does not lower its quality as a production-ready framework. Coupled with other packages and plugins found in npm registry, we can create a professional website in no time.

Using create-react-app with react-router allows creating routes for our React.js application. This blog will focus on SSR with code bundling to improve performance. Furthermore, we will deploy to Heroku using the production build from npm run build, which acts as a static site rather than dynamic site (npm start).


tl;dr

  1. Read this example on how to enable Server Side Rendering through React Router
  2. Install serve (npm i serve) for serving built static web
  3. Update the Heroku Procfile to web: serve -s build

1. create-react-app with react-router

react-router enables create-react-app application to use routing, primarily Client Side Routing (CSR). However, in this post, we are only going to use react-router for its Server Side Routing (SSR).

A little note about CSR vs SSR

In shorthand, in Server Side Routing (SSR), the user requests a whole new page, while in Client Side Routing (CSR), the user only request changes in data and the page changes accordingly. So, SSR requires the user to download more data (and thus slower) compared to CSR.

react-router focuses on CSR, but we can use it as SSR as well. You can find the tutorial for this in their website (SSR up until Nested Routes section).

SSR through Code Bundling

CSR might have slower initial load since the user needs to download all data, even the ones that they never going to see. Let's say there are 3 routes: /home, /about, and /user. If we use react-router as it is from the tutorial, then the user will download all content in those three pages, although they only open one of the page. Code bundling will solve this issue. Refer this legacy docs for how to implement code bundling.


2. How Heroku Runs create-react-app

This is how Heroku runs create-react-app on default (applies to with or without react-router).

  1. Heroku automatically detects that the app is a Node.js app
  2. Heroku runs npm install, followed by npm run build if it is defined in package.json. create-react-app already defined npm run build.
  3. Heroku looks for Procfile file and all defined processes. Usually this file only contains a single line: web: npm start.
  4. Heroku will run their dynos (server) based on one of these processes.

However, this is not optimized since we are using the development build. Heroku did build the production build, but they still use the development build (note the web: npm start command in Procfile).

Run the Production Build (Static Site) Locally

Using npm start, the website will be run as a dynamic site. If your website has no dynamic or back-end code, then we can build it to be a static website.

First, we need to build the app first by running npm run build. It will create a new directory called build which contains static HTML, CSS, JavaScript, public files, etc. We can not just open the index.html file and expect it to work. We need to run a static server.

There are many different ways to run a static server. In Node.js, you can install packages like http-server, static-server, and serve. In Python, you can use http.server.

We are going to use serve as it is fast and simple to use.

npm install serve
serve -s build
Enter fullscreen mode Exit fullscreen mode

3. Run the Production Build (Static Site) on Heroku

Heroku automatically runs npm run build, but it still run the application using npm start, which is not optimized. We can use serve to run the production build (static site).

Add this dependency in package.json (or just run npm install serve if you're not sure about the version).

"serve": "^14.2.0",
Enter fullscreen mode Exit fullscreen mode

Update the Procfile.

web: serve -s build
Enter fullscreen mode Exit fullscreen mode

That's It

And those are the reasons behind why I did those steps to run create-react-app with react-router on Heroku.

Alternative without serve (Using Express)

Instead of installing serve or other static site server, we can create a server.js file in the root directory.

const express = require('express');
const path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, 'build')));

app.get('/', function (req, res) { // marked
    res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.listen(9000);
Enter fullscreen mode Exit fullscreen mode

If you use react-router, then change the marked line to app.get('/*', function(req, res)) {.

Also don't forget to update the Procfile.

web: node server.js
Enter fullscreen mode Exit fullscreen mode

And that's it! Now Heroku will run the production build without installing serve or any other application.

Top comments (0)