# Setting up a React (Vite) Monorepo project with Yarn Workspaces

### 🤔 What is a Monorepo Architectural Concept?

Monorepo is an architectural idea in which all of a project's code is kept in a *single repository* as opposed to being dispersed over several repositories. Code for various features, settings (such as web and mobile), and even languages can be included in this. By keeping all of the code in one location, the objective behind this notion is to simplify dependency management and *enhance teamwork*. Monorepo also makes it simple to share code among various project components and can streamline the update-releasing procedure. Implementing Monorepo is possible with the aid of tools like Lerna, Yarn Workspaces, and NX Workspaces.

### 🤔 Benefits of using Monorepo Architectural Concept?

A monorepo architectural design has various advantages for a project:

* **Better collaboration**: Team members can work together and share code more easily when the code is all in one location.
    
* **Better management of dependencies**: A monorepo makes it simpler to manage dependencies between different project components. The likelihood that various sections of the code would malfunction as a result of modifications to shared dependencies is decreased.
    
* **The release process is made simpler**: Since a monorepo makes it possible to release updates to the entire project at once rather than having to do so separately for each repository.
    
* **The codebase has a single source of truth**: Monorepo gives the code a single home, making it simpler to comprehend the architecture and design of the codebase.
    
* **Better scalability**: Monorepo makes it possible to expand without having to create new repositories.
    
* **Reusability**: Monorepo enables the sharing of common code between teams and projects, improving reuse and speeding up development.
    

### 🤔 What is Yarn Workspaces?

The **Yarn** package manager has a feature called *Yarn Workspaces* that enables the management of many packages within a single repository, or **workspace**.

Developers can simply manage and share dependencies across those packages thanks to the ability to put related packages together in a monorepo structure.

Yarn Workspaces enables you to manage the codebase of your project by having a *single root* `package.json` file and several `package.json` files in various subfolders that contain the code for distinct packages.

Although each package may have its own `scripts` and `dependencies`, they may also share these elements with other packages in the workspace.

This makes it simple to manage dependencies in a centralized manner and to share code among various project components.

Additionally, Yarn Workspaces makes it simple to link different packages together so you can test and develop them alone as well as as a component of a larger project. It also enables simple package versioning and publishing to a package manager like npm.

### ⚙️ The Setup

> ❗️ In this setup we are going to create a React monorepo setup using yarn workspaces and applications created with vite.
> 
> We will be creating this project in **three** parts. **two** will be subparts of the **main** application and **one** being a common repository, more like a container for reusable components for the other **two** parts.
> 
> Here is a visual representation of the monorepo structure that we are going end up with after completing this demonstration.
> 
> ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673536871192/2c54dce6-c88e-4ca2-a451-28066b7eed6e.png align="center")

#### Step 1️⃣:

* Create a new folder and open it with your favourite code editor. This will be the project's `root` folder.
    
* Inside the root folder create a new `package.json` file and add the following contents to it:
    
    ```json
    {
      "private": true,
      "workspaces": {
        "packages": [
          "./packages/main",
          "./packages/app1",
          "./packages/app2",
          "./packages/common"
        ]
      },
      "scripts": {
        "main": "yarn workspace main dev"
      }
    }
    ```
    

#### Step 2️⃣:

* Create a new folder inside the root and name it `packages`
    

Create **four** more folders inside `packages` and name them:

* app1
    
* app2
    
* common
    
* main
    

> **main** is going to be our project application.
> 
> **app1** is going to be a sub project (or) a feature of the main application.
> 
> **app2** is going to be the second sub project (or) a feature of the main application.
> 
> **common** is going to be a repository containing reusable components likely to be used by both app1 and app2.

* After creating the folders, move into each folder one at a time and run
    
    ```bash
    npm create vite@latest
    ```
    
    to initialize a new project using vite. Follow the prompts and give a suitable choice of framework along with a suitable variant. For this demonstration, I will be choosing `react` as the framework and `javascript` as the variant.
    
* Once done, the structure of every project folder under `packages` should look like this:
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673537864830/6d48e85a-8a1c-4376-96a4-4235edc3850f.png align="center")

#### Step 3️⃣:

* Clean up and rename the files in the `src/` folder of **app1**, **app2** and **common.**
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673538144118/acd2dab4-b895-4c35-a828-e706945092c0.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673538193014/3559a5f5-2021-4ba9-8deb-addb3be92f4e.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673538284028/6e1325f4-4fe4-4bd0-983c-7660242c9fa6.png align="center")

* Add the following contents to the following files:
    
* `app1/src/App1.jsx`
    
    ```javascript
    import React from 'react';
    import { Button } from 'common';
    
    export function App1() {
      return (
        <div>
          <h1>App 1</h1>
          <Button text='App1 Button test' />
        </div>
      );
    }
    ```
    
* `app1/src/main.jsx`
    
    ```javascript
    export { App1 } from './App1';
    ```
    
* `app1/package.json`
    
* add a new property for entry
    
    ```json
    {
        ...
          "main": "./src/main.jsx",
        ...
    }
    ```
    
    ```json
    "dependencies": {
    // dependency name should be same as the repo's name in its            package.json
    
    // * symbolizes any version of the package, but you can meantion any version the repository supports
    
        ...
           "common": "*",
        ...
    }
    ```
    
* `app2/src/App2.jsx`
    
    ```javascript
    import React from 'react';
    import { Button } from 'common';
    
    export function App2() {
      return (
        <div>
          <h1>App 2</h1>
          <Button text='App2 Button test' />
        </div>
      );
    }
    ```
    
* `app2/src/main.jsx`
    
    ```javascript
    export { App2 } from './App2';
    ```
    
* `app2/package.json`
    
    ```json
    {
        ...
          "main": "./src/main.jsx",
        ...
    }
    ```
    
    ```json
    "dependencies": {
    // dependency name should be same as the repo's name in its            package.json
    
    // * symbolizes any version of the package, but you can meantion any version the repository supports
    
        ...
           "common": "*",
        ...
    }
    ```
    
* `common/src/components.jsx`
    
    ```javascript
    import React from 'react';
    
    export function Button(props) {
      return <button>{props.text}</button>;
    }
    ```
    
* `common/src/main.jsx`
    
    ```javascript
    export { Button } from './components';
    ```
    
* `common/package.json`
    
    ```json
    {
        ...
          "main": "./src/main.jsx",
        ...
    }
    ```
    
* No additions under dependencies in this project.
    

> `scripts` other than *build* in `package.json` of **app1**, **app2** and **common** can be deleted as we won't be starting these vite applications independently. These repositories are meant to be exported and imported into **main** which will be served to the thin client.

#### Step 4️⃣:

* Prepare the **main** application
    
* The structure of the **main** should be looking like this with the following contents:
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673539045155/6d2e94a9-630f-48af-897c-51e82fb992da.png align="center")

* `main/src/App.jsx`
    
    ```javascript
    import React from 'react';
    import './App.css';
    import { App1 } from 'app1';
    import { App2 } from 'app2';
    
    function App() {
      return (
        <div>
          <h1>Main Application</h1>
          <App1 />
          <App2 />
        </div>
      );
    }
    
    export default App;
    ```
    
* `main/src/main.jsx`
    
    ```javascript
    import React from 'react'
    import ReactDOM from 'react-dom/client'
    import App from './App'
    import './index.css'
    
    ReactDOM.createRoot(document.getElementById('root')).render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
    )
    ```
    
* `main/package.json`
    
    ```json
    "scripts": {
        "dev": "vite",
        "build": "vite build",
        "preview": "vite preview"
      },
    // dependency name should be same as the repo's name in its            package.json
    
    // * symbolizes any version of the package, but you can meantion any version the repository supports
    "dependencies": {
        ...
            "app1": "*",
            "app2": "*",
        ...
      },
    ```
    

#### Step 5️⃣:

* Back inside the `root` directory, run:
    
    ```bash
    yarn
    ```
    
    to download all the dependencies needed by the whole project. you will notice that a `node_modules` folder will be added to the root folder. Also a `node_modules` folder will be added to each of **app1**, **app1**, **common** and **main**
    
    > ❗️ When you run `yarn` in the root folder of a monorepo, it will install all the dependencies defined in the root `package.json` file and all the dependencies defined in the `package.json` files of all the packages in the `packages` folder.
    > 
    > In order to do so, yarn will create a `node_modules` folder in the root folder, and then it will create a `node_modules` folder inside of each of the packages in the `packages` folder.
    > 
    > This is done to keep the dependencies of each package separated and isolated from each other. By doing so, it will allow each package to have its own version of the dependencies, and avoids conflicts that could happen if they were all installed in a single global `node_modules` folder.
    > 
    > Additionally, this allows each package to have its own set of dependencies and to have a specific versions of those dependencies that can be different from other packages, while still being able to share common dependencies and have them in a centralized location.
    

#### Step 6️⃣:

* Fire up the main application using:
    
    ```bash
    yarn main
    ```
    
* This launches the monorepo application 🎉
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673540045703/a54820a9-2469-4358-ab8b-477f3abd0bf6.png align="center")

### 💭 Conclusion

In conclusion, implementing a monorepo architecture can significantly enhance teamwork and codebase management. Developers may simply share code and manage dependencies among various areas of the project by keeping all of the code in one repository.

Better scalability, better dependency management, enhanced collaboration, a streamlined release process, and reusability are all possible with monorepo. Monorepo might not be appropriate for all projects, so it's crucial to keep that in mind and always balance the benefits and drawbacks before opting to utilise it.

### 🔗 GitHub

[https://github.com/adeeshsharma/react-monorepo-setup](https://github.com/adeeshsharma/react-monorepo-setup)
