Deploy unlimited React Apps using single ExpressJS Server on Heroku

Have you ever tried creating multiple portfolios using React?
And then ended up deploying each on a separate server 🥲
In this blog, we will learn how you can utilize the power of a single ExpressJS/NodeJS server and serve multiple React apps.
(For deployment, I am using Heroku, feel free to use any other)
How it works? 🤔
- Each React app creates its own
buildfolder - Each
buildfolder generated will be served at a separate subpath by the single server
And that's it!

Step 1: Preparing React apps
To allow our ExpressJS serve these apps, we need to specify a unique build path for each app.
For instance, 3 apps, first is ran at root /, second at /app2 & third at /app3

To make this possible the build generated should include this relative path.
Update the build command in package.json for each additional React app.
Add PUBLIC_URL=/<something> to package.json build property.
For instance,
for second app, scripts property in package.json will look something like
"scripts": {
...
"start": "PORT=3001 PUBLIC_URL=/app2 react-scripts start",
"build": "PUBLIC_URL=/app2 react-scripts build",
...
},
& for third app
"scripts": {
...
"start": "PORT=3001 PUBLIC_URL=/app3 react-scripts start",
"build": "PUBLIC_URL=/app3 react-scripts build",
...
},
Step 2: Preparing Server
For this tutorial, I'll be using ExpressJs/NodeJs server, but the concept can applied to any server. That is
Each
buildfolder generated will be served at a separate subpath by a single server
In your parent server file (I am using server.js), for each additional app add the following
const buildPath = path.join(__dirname, '<react app folder path>/build')
app.use('/<your build path>', express.static(buildPath))
app.get('/<your build path>/*', function(req,res) {
res.sendFile(adminBuildPath)
})
For instance, for our 3 React apps example, server.js will look like:
...
const app1BuildPath = path.join(__dirname, '../app1/build')
// serve static content of app 1 at root \ path
app.use(express.static(app1BuildPath))
app.get('/*', function(req,res) {
res.sendFile(app1BuildPath)
})
const app2BuildPath = path.join(__dirname, '../app2/build')
// serve static content of app 2 at root \app2 path
app.use('/app2', express.static(app2BuildPath))
app.get('/app2/*', function(req,res) {
res.sendFile(app2BuildPath)
})
const app3BuildPath = path.join(__dirname, '../app3/build')
// serve static content of app 3 at root \app3 path
app.use('/app3', express.static(app3BuildPath))
app.get('/app3/*', function(req,res) {
res.sendFile(app3BuildPath)
})
...
BONUS: Heroku deployment
Prerequisites: Heroku CLI
Now that everything is prepared, let's deploy our changes on Heroku.
Heroku CLI makes deployment a lot easier. It runs 3 commands, namely install, start & build. Hence, we need to fix the parent package.json file and include those.
install: should install all the dependencies of all the appsstart: should start the node/express serverbuild: should run build command for each app
For instance, for the 3 apps example, it will look like:
...
"scripts": {
"start": "node server/server.js",
"install": "cd server && npm i && cd ../app1 && npm i && cd ../app2 && npm i && cd ../app3 && npm i",
"build": "cd app1 && npm run build && cd ../app2 && npm run build && cd ../app3 && npm run build"
},
...
To initiate the deployment run the following in your Terminal
If you don't have an Heroku app already created
// creates an Heroku app
heroku create
Finally, to deploy from the main branch (update branch name if using something else, like master)
git push heroku main
For more details, you can refer this video
Happy coding!!
