If you’ve ever worked on a project with multiple
package.json files, you might know the pain of juggling multiple terminal tabs, remembering which commands start up which server, or handling CORS errors.
Luckily, there are a few tools available to us that can alleviate some of these headaches. In this post, we’ll go over three things you can do to optimize your development workflow when working on a project with a React front end (specifically, Create React App) and Node back end.
Setting the scene#
Let's say we're working in a monorepo with two
package.json files — one is in a
client directory for a React front end powered by Create React App, and one is in the root of the repo for a Node back end that exposes an API that our React app uses. Our React app runs on
localhost:3000 and our Node app runs on
localhost:8888. Both apps are started using
The directory structure looks something like this:
Since we have two
package.json files, this means that to have our front end and back end up and running we need to make sure we've run
npm install and
npm start in both the root directory and the
client directory. Let’s take a look at how we can streamline this.
1. Run two servers concurrently#
One improvement we can make to our development workflow is adding a build tool to run multiple npm commands at the same time to save us the hassle of running
npm start in multiple terminal tabs. To do this, we can add an npm package called Concurrently to the root of our project.
At the root of our project, we’ll install it as a dev dependency.
Then in our root
package.json scripts, we’ll update our
start script to use Concurrently.
Now, we have three npm scripts.
npm run server starts up our Node app,
npm run client runs
npm start in the
client directory to start up our React app, and
npm start runs both
npm run server and
npm run client at the same time. Here’s what it should look like now when running
npm start in the root of our directory.
2. Install front end and back end dependencies with one
Another aspect of our workflow we can improve is dependency installation. Currently, we need to manually run
npm install for each
package.json file we have when setting up the project. Instead of going through that hassle, we can add a postinstall script to our root
package.json to automatically run
npm install in the
client directory after installation has finished in the root directory.
Now, when we install our monorepo, all we need to do to get up and running is run
npm install then
npm start at the root of the project. No need to
cd into any other directories to run other commands.
3. Proxy API requests from the back end#
As we mentioned above, our Node back end exposes API endpoints that are used by our React app. Let’s say our Node app has a
/refresh_token endpoint. Out of the box, if we tried to send a
GET request to
http://localhost:8888/refresh_token from our React app on
http://localhost:3000, we would run into CORS issues.
CORS stands for Cross-Origin Resource Sharing. Usually, when you encounter CORS errors, it's because you are trying to access resources from another domain (i.e.
http://localhost:8888), and the domain you're requesting resources from is not permitted.
To tell the development server to proxy any unknown requests to our API server in development, we can set up a proxy in our React app's package.json file. In
client/package.json, we’ll add a proxy for http://localhost:8888 (where our Node app runs).
Now, if we restart the server and set up a request to our Node app's
/refresh_token endpoint (without the
http://localhost:8888) using fetch(), the CORS error should be resolved.
The next time you work on a monorepo project like this, try out these three tips to streamline your development workflow!
Be sure to check out our new course being released soon, Build a Spotify Connected App, where we apply these concepts to build a real-world, full stack web app!