Published on

Hosting my full stack React Node.js Socket.io Application on Heroku

Last Modified on
Last modified on
Authors
Chattr Node.js socket.io app
Photo by Maria D. Campbell on Interglobalmedia

I just completed building a full stack React, Node.js, Socket.io application and successfully hosted it on Heroku. At first I tried creating a droplet on Digital Ocean and then hosting my application there. However, I would have had to use my Digital Ocean IP as my front end URL OR an actual domain in order to purportedly host it there, but I did not even get to that point. When I tried to add Nginx to the droplet, it just did not happen. And there is no free tier for this kind of application there. It costs $6/month at the least, and perhaps even more, depending on the traffic and usage. At one point, I no longer even was able to log into my droplet either! I think I was maxed out. Suffice it to say, it was one big headache.

I decided to go back to Heroku and host there. They have made many updates and changes. There no longer is a free tier, but the cheapest monthly charge is $5/month, which is still $1 less than Digital Ocean, and also NOT a huge headache. I’m not saying that I would never try using Digital Ocean. The headache and use case was just not worth it for this project. On the other hand, it might never be worth it!

Anyway, this time I had to install Heroku using Homebrew. I don’t remember doing it that way previously, but it was a breeze.

I also had to make some changes to the structure of the application. When I previously had created full stack Node.js applications, I had used views with templating engines such as EJS, for example, and not React. So this time, I had to make sure that I could run both the front and back ends of the application in one place, and that meant refactoring the app structure and local scripts a bit.

I searched for guidance regarding this refactoring, and I found a great solution on Dev.to! The article is entitled How to deploy React + Node.js application to Heroku and is written by Yogesh Chavan.

I had structured my application with a client folder for the React front end, and a server folder for the Node.js back end. I had never had to set things up that way when using views for the application "front end". But how was I going to be able to run the whole application (including React) using only one port?

According to Yogesh, (and I think I had done something similar way back when), I just needed to make sure that I (or Heroku in production) ran a build of the latest changes made to the React application which would be saved on the client side in the application's root folder. And after the the build is created, the script cds (changes directory) into the server folder and installs the necessary application npm modules. That meant first dragging out the contents of the client folder and placing it in the root of the project. That made the package.json of the (former) client folder the root package.json. That was very important to do.

I had to make sure that I removed the value of my socket_url variable and set it to an empty string.

I had to make sure to change the name of the default React start script that comes with create-react-app to “start-client” so that it would not be used!

Next, I had to change the value of the default React build script that came with create-react-app. Initially, it was:

"build": "react-scripts build”

I changed it to:

"build": "react-scripts build && (cd server && npm install)"

What this script does is it creates a build folder at the root of my application/project (run the ls command at the root of yours and see for yourself!), and I added the following to my index.js file in the server directory, which contains the code for my Node.js server:

const buildPath = path.join(__dirname, '..', 'build')
app.use(express.static(buildPath))

This code ensures that the contents of the build folder are accessed, and if it contains an .html file (which it does), the Express server renders the contents of that file when http://localhost:8000 is accessed. And my Node.js server is (already) running on port 8000. So because I removed the value of the React URL containing its port 3000, both front and back end are running now on port 8000.

The value of the buildPath points to the root of the server folder, represented by __dirname, which is where the index.js file of the back end server side code resides, and ‘..’ represents moving out of the server directory into the root directory of the application itself, where the front end build directory resides, after running the npm run build script at the root of the project.

app.use(express.static(buildPath)) makes sure that Express renders the contents of the index.html file inside the build folder.

I also could have removed all reference to the cors npm module, since the application is only running on one port, but I am keeping it for now.

To view the application on Heroku, please visit https://socketio-realtime-node-chat.herokuapp.com/.

Note: I am currently on Apple M1 Max, macOS Ventura 13.1 (soon 13.2). And originally I had Xcode 13.4.1. However, when I tried to deploy my application to Heroku, it let me know that my version of Xcode was too old, and that I should update it to the latest version. This of course has to do with Git and CLT. So once I updated Xcode, I no longer got any error messages regarding Xcode. So make sure you have updated to the latest version of Xcode for your macOS before deploying applications to Heroku via your macOS!