Serving multiple ReactJS apps with Express

I am currently working on a web portal for showcasing our teams’ different projects, white-papers and reports. Given the limited scope of the project, we thought it might be a good idea to try it with a full JavaScript stack of  MongoDBExpress and ReactJS.

Since the site needed both a user facing portal and an admin portal, we started building both of those in parallel but as separate projects. The goal was to keep the admin portal independent of the actual site itself. The pages on the site are also more or less completely defined in JSON schemas so it could be reused in the future if we ever wanted to use it for a different project or release it as an open source project.

The Create-React-App library from Facebook was really useful for a pretty painless start to the projects.

Proxying calls to the API

The first issue I ran into was accessing Express that was running on a different port (3000) than Create-React-App’s development server (3001). Since the browser considered these two different sites, browser security wouldn’t let be make API calls to the server from the client. Figuring it was a problem for later, I just allowed the dev server to handle CORS requests using something like:

app.use(function(req, res, next) { 
    res.header("Access-Control-Allow-Origin", "*"); next(); 
});

This worked for all GET requests but completely failed when I tried to POST JSON from the client. Turns out when sending JSON, the browser pre-flights the POST request with an OPTIONS request that I was not handling at all. As found in the MDN docs:

The [CORS] specification mandates that browsers "preflight" 
the request, soliciting supported methods from the server with an 
HTTP OPTIONS request method, and then, upon "approval" from the server, 
sending the actual request with the actual HTTP request method.

Turns out, all the headache was for nothing. Create-React-Apps allows you to proxy calls to a dev server by adding a proxy line in your package.json

"proxy": "http://localhost:3000/",

Packaging React Apps for different server paths

Another issue was that Create-React-Apps by default assumes the final built app will be served from the root of the server. It took a bit of finding out that the it does allow you to set the folder path for your app on the server using the homepage field in the package.json:

"homepage": "http://localhost:3000/admin",

Allowing Express to serve multiple React Apps

Finally as we tried to deploy the front end and the admin app, we ran into another issue. Since Express needed to serve front-end from the server root, admin from the /admin/ path and also a bunch of different api responses from /api urls, we had to do a bit of trial and error to get the pathing for the resources right. Our final response paths for the Express app look like this:

// API end points defined first
app.get("/api/projects",  (req, res)=>{})
app.post("/api/project",  (req, res)=>{})

// Admin paths
app.use('/admin/', express.static(path.join(__dirname, 'admin')))
app.get('/admin/*', function (req, res) {
 res.sendFile(path.join(__dirname, './admin', 'index.html'));
});

// Site path
app.use('/', express.static(path.join(__dirname, 'front-end')))
app.get('/*', function (req, res) {
 res.sendFile(path.join(__dirname, 'front-end', 'index.html'));
});

This is still work in progress and I am sure a lot more learnings will come going forward, but at right now, with the first version of the site deployed to our dev server, I am gonna get a well earned beer 🙂

 

Author: Arpit Mathur

Arpit Mathur is a Principal Engineer at Comcast Labs where he is currently working on a variety of topics including Machine Learning, Affective Computing, and Blockchain applications. Arpit has also worked extensively on Android and iOS applications, Virtual Reality apps as well as with web technologies like JavaScript, HTML and Ruby on Rails. He also spent a couple of years in the User Experience team as a Creative Technologist.

2 thoughts on “Serving multiple ReactJS apps with Express”

  1. Hey Arpit,
    thanks for this very understandable tutorial. Is there any progress you made on this already published on your blog? Please contact me if you want to talk about this topic and maybe some aspects that are coming (and I have already tackled) like SSR. Since your latest posts are about React-Native, maybe you’ve found a solution to make it work with this solution as well?

    All the best,
    Bastian

    Like

Leave a comment