How to deploy a Reactjs and Express App to Heroku

Adel ak
3 min readDec 28, 2019

--

Photo by Bill Jelen on Unsplash

There is no easy way to say this but I hate deploying to Heroku, I’ve seen many ways to deploy a react and express app to Heroku, unfortunately, none of them seemed to work.

Well, I found a way to do it 🎉, good thing I’m here to guild you step by step.

Before we get into it, here is an itz bitz info of the project, it's a school administration app which provides a user-friendly interface for managing a school’s database courses, users can view all courses and can create/update and delete courses once they sign up.

The application was created using React which renders the UI and ExpressJS as the server, the server is a restful API which runs a relational database with the help of sequelize which is a promise-based Node.js ORM.

well enough said, let's get down to business.

Step 1 — Folder Structure

The folder structure your working with should look something like this.

school-admin
|
---api <--- your restful api
|
---client <--- your react app
|
--- README

If the root folder looks something like that, your off to a good start, next you will need to initialize a package.json file using npm init -y.

Once initialization is completed, let's add two properties to the script.

start, and heroku-postbuild

"scripts": {  "test": "echo \"Error: no test specified\" && exit 1",  "start": "cd api && npm install && npm start",  "heroku-postbuild": "cd client && npm install && npm run build"}

Also add an engine property with our node version, to get your node version, you can simply open a command line and run node -v

"engines": {  "node": "10.17.0"}

Step 2 — Client Folder

Let’s move to the package.json file located in the client folder, we are going to set up the proxy to our server. Add the "proxy" property to the package.json file.

The value is going to be the localhost your API server is running on, mine is running on 5000.

"proxy": "http://localhost:5000"

Now in your react app, where ever you were making HTTP requests from, you should change the URL from http://localhost:5000/api/users to /api/users

That should be it in this folder, but since we are in the client folder, you might as well just build your react app by running npm run build in the command line (for testing purposes later on).

Step 3 — API Folder

For the package.json located in this folder, just confirm the start script has the value of node app.js.

"scripts": {  "start": "node app.js"}

Now we CODE!!

In your server file whether it’s app.js, index.js or server.js, let’s request the path API and serve static files from the client build folder.

const path = require('path');app.use(express.static(path.join(__dirname, '../client/build')));

Also add a catch-all route to serve the index.html file from the client build folder

app.get('*', (req, res) => {  res.sendFile(path.join(__dirname, '../client/build/index.html'));});

Any routes that don’t match, it will send back the index.html

NOTE!!!!

It's important to choose where to place the catch-all route, for example

app.get('*', (req, res) => {...});app.get('/api/users', (req, res) => {...});

If you try to get data from /api/users, it won’t work because the catch-all route is above the api route, visiting /api/users will match the catch-all route

The best place to put it is above the error handler middleware

app.get('/api/users', (req, res) => {...});
app.get('/api/courses', (req, res) => {...});
app.get('/api/courses/:id', (req, res) => {...});
//api routes above

app.get('*', (req, res) => {...});
//error handler's belowapp.use((req, res) => { res.status(404).json({ message: 'Route Not Found' });});app.use((err, req, res) => { res.status(err.status || 500).json({ message: err.message, error: {} });});

Step 4 - Test, Then deploy

Test it out and see if the server responds the index.html file when we visit localhost:5000 , open up the command line and run npm start.

if(app_runs){
console.log('hip hip hooray, go ahead and deploy the app');

}else{

console.log('follow the steps once more' || DM me in twitter and we will figure it out @adel_xoxo);
}

That should be it my fellow citizens.

I apologize if this was an uncomfortable read/experience, as it's my first post.

That diamond is my ticket out of this… godforsaken continent.

~Danny Archer

--

--