Monorepo and its setup for MERN stack
Tags: monorepo
Published: 2021-05-15 11:47:34

#What is monorepo?
Monorepo is a single repository that will store all the code base and assets. For example, If you're making a full-stack app, you can store both frontend and backend parts in a single repository.

#Why monorepo?

###Dependency management
You can manage all of your code dependencies from a single source, you don't have to change the directory to add or remove any dependency

###Server starting
You can start all the servers from a single command. For example, if you want to start the servers of both ReactJS and Express, you can do it with a single command.

###Symlinks
Any package can be a dependency to another without going through npm or any package manager.

###Collaboration
A single repository is very much helpful in sharing and collaborating because developers can access all codes and assets from a single source.
That's why event tech giants like Google is also using monorepos.

###Speed
Monorepo will increase the speed of the development as you do not have to write different commands in different directories. Also, one can change across multiple files together.

##Setup
I am using Yarn workspace here to explain monorepo setup for a MERN stack project.

Structure :
root-folder >
     - api-folder
     - app-folder 

1.In the root folder, make a folder name packages and inside it, make your `client` and `api` folders.

2.In the package.json file of both client and api, change the name to the `@[rootfolder_name]/client` and `@[rootfolder_name]/api` respectively. For reference, this is my package.json of both folders, here my root folder name is `videolibrary` :

client>package.json
```javascript
{
  "name": "@videolibrary/client",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.2.0",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
```

api>package.json
```javascript
{
  "name": "@videolibrary/api",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "body-parser": "^1.19.0",
    "cors": "^2.8.5",
    "dotenv": "^9.0.1",
    "express": "^4.17.1",
    "mongoose": "^5.12.5",
    "nodemon": "^2.0.7"
  },
  "scripts": {
    "serve": "nodemon index.js",
    "start": "node index.js"
  }
}
```

3.In the root folder, install a package called `concurrently`.
Concurrently is a package that can run multiple npm scripts simultaneously. Here, we are using it to run React and Node servers simultaneously.

4.In the package.json of the root folder,
 * Add `"workspaces" : ["packages/*"]`
 * Add 
```javascript
"scripts": 
{
    "app": "yarn workspace @[rootfolder_name]/client start",
    "server": "yarn workspace @[rootfolder_name]/api serve",
    "build-app": "yarn workspace @[rootfolder_name]/client build",
    "build-server": "yarn workspace @[rootfolder_name]/api build",
    "start": "concurrently --kill-others-on-fail \"yarn client\"  \"yarn server\"",
    "start:server" : "yarn workspace @[rootfolder_name]/api start"
}
```
 * Add `"engines": {
    "node": "14.15.0"
  } `

For reference, you can see my root package.json file :
```javascript
{
  "name": "videolibrary",
  "version": "1.0.0",
  "license": "MIT",
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  "scripts": {
    "app": "yarn workspace @videolibrary/app start",
    "server": "yarn workspace @videolibrary/api serve",
    "build-app": "yarn workspace @videolibrary/app build",
    "build-server": "yarn workspace @videolibrary/api build",
    "start": "concurrently --kill-others-on-fail \"yarn app\"  \"yarn server\"",
    "start:server" : "yarn workspace @videolibrary/api start"
  },
  "engines": {
    "node": "14.15.0"
  },
  "dependencies": {
    "concurrently": "^6.0.2"
  }
}
```

That's it, you are good to go now! Your monorepo is ready to use.