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 MongoDB, Express 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 🙂
Thank you for this, was just working out this idea in my head. This really helped
LikeLiked by 1 person
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
LikeLike