React LogoMonorepo Yƶnetimi

Monorepo Management is the practice of hosting multiple different projects or applications (e.g., a web application, a mobile application, a shared UI library, an API, etc.) within a single version control repository (usually Git). Traditionally, each project has its own separate repository (polyrepo or multi-repository).

Why Use a Monorepo?

1. Easy Management of Shared Code: This allows you to easily share and synchronize code snippets, such as common UI components, utility functions, or types, across all projects. When a change is made, all projects affected by that change are instantly updated.
2. Atomic Commits: You can make logically related changes across multiple projects or packages in a single commit. For example, it's possible to commit a change to a shared library and its adaptation in an application that uses that change simultaneously.
3. Simplified Dependency Management: All projects and packages can share the same `node_modules` directory or a virtual `node_modules` structure. This reduces dependency conflicts and saves disk space.

4. Consistent Toolset and Configuration: The same build tools, linting rules, testing frameworks, and coding standards can be applied across all projects, unifying the development experience.

5. Easier Refactoring: When refactoring a component or service, it's easier to see and apply changes to all affected projects in one place.

6. Centralized CI/CD: It's simpler to establish a centralized CI/CD (Continuous Integration/Continuous Deployment) pipeline for all projects in a single repository.

Challenges of a Monorepo:

1. Repository Size and Performance: The repository size can grow over time, which can slow down operations like git clones.

2. Build and Test Times: Compiling and testing all projects or dependencies each time can take a long time. Tools capable of smart compilation (compiling only the changed parts) mitigate this issue.

3. Access Control: Ensuring that a specific team only has access to their own project can be more complex, as all the code is in a single repository.

4. Tool Complexity: To effectively manage monorepos, specialized tools such as Lerna, Nx, Turborepo, Yarn Workspaces, or pnpm Workspaces are needed.

Monorepo Management Tools:

* Yarn Workspaces / pnpm Workspaces / npm Workspaces: Provides basic dependency management and package hoisting. Ideal for projects with multiple packages.

* Lerna: A popular tool for managing package dependencies, releasing versions, and running commands on packages in a monorepo.
* Nx (Nrwl Extensible Dev Tools): Provides advanced build optimizations, smart recompilation, code generation, and a robust framework for a range of technologies (React, Angular, Node.js, etc.). It excels in large and complex monorepos. * Turborepo: A next-generation monorepo tool featuring high-performance build caching and parallel task execution capabilities.

These tools help manage the complexities of a monorepo, optimize build times, and improve the developer experience.

Example Code

// This example demonstrates a monorepo structure and how a React application uses a shared UI component.
// Let's assume we have a root directory called "my-monorepo".
// It's configured using Yarn Workspaces.

// 1. my-monorepo/package.json (Root Directory)
// The root package.json file defines all subdirectories under the "packages" folder in the monorepo with the "workspaces" attribute.
// The "nohoist" setting ensures that some dependencies (which can be mandatory in React-based projects) are not pushed to the root level.
```json
{
"name": "my-monorepo",
"version": "1.0.0",
"private": true,
"workspaces": [
"packages/*"
],
"scripts": {
"start:web": "yarn workspace web-app start",
"build:web": "yarn workspace web-app build",
"build:shared-ui": "yarn workspace shared-ui build"
},
"devDependencies": {
"lerna": "^6.0.0" // Additional tools like Lerna can also be used
}
}
```

// 2. my-monorepo/packages/shared-ui/package.json
// This file defines the package of a shared UI library (for example, the Button component) within the monorepo.
```json
{ 
"name": "shared-ui", 
"version": "1.0.0", 
"main": "dist/index.js", 
"module": "dist/index.esm.js", 
"files":[ 
"dist" 
], 
"scripts": { 
"build": "rollup -c", 
"dev": "rollup -c -w" 
}, 
"devDependencies": { 
"react": "^18.2.0", 
"react-dom": "^18.2.0", 
"@rollup/plugin-babel": "^6.0.0", 
"@rollup/plugin-node-resolve": "^15.0.0", 
"rollup": "^3.0.0", 
"@babel/core": "^7.20.0", 
"@babel/preset-react": "^7.18.0" 
}
}
```

// 3. my-monorepo/packages/shared-ui/src/Button.js
// A simple React component in the shared UI library.
```javascript
// my-monorepo/packages/shared-ui/src/Button.js
import React from 'react';

function Button({ children, onClick, variant = 'primary' }) { 
const buttonStyle = { 
padding: '10px 20px', 
borderRadius: '5px', 
border: 'none', 
cursor: 'pointer', 
backgroundColor: variant === 'primary' ? '#007bff' : '#6c757d', 
colour: 'white', 
fontSize: '16px' 
}; 

return ( 
<button style={buttonStyle} onClick={onClick}> 
{children} 
</button> 
);
}

export default Button;
```

// 4. my-monorepo/packages/shared-ui/src/index.js
// Main export file of the shared UI library.
```javascript
// my-monorepo/packages/shared-ui/src/index.js
export { default as Button } from './Button';
```

// 5. my-monorepo/packages/web-app/package.json
// This file defines the package for a React web application within the monorepo.
// Note how the "shared-ui" package is referenced as a dependency.
// The "workspace:^" syntax is the standard way to reference a local package in Yarn Workspaces.
```json
{ 
"name": "web-app", 
"version": "0.1.0", 
"private":true, 
"dependencies": { 
"react": "^18.2.0", 
"react-dom": "^18.2.0", 
"react-scripts": "5.0.1", 
"shared-ui": "workspace:^1.0.0" // Reference to shared UI package in Monorepo 
}, 
"scripts": { 
"start": "react-scripts start", 
"build": "react-scripts build", 
"test": "react-scripts test", 
"eject": "react-scripts eject" 
}, 
"eslintConfig": { 
"extends": [ 
"react-app", 
"react-app/gesture" 
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
```

// 6. my-monorepo/packages/web-app/src/App.js
// Demonstrates how a React web application imports and uses the 'Button' component from the shared UI library.
````javascript
// my-monorepo/packages/web-app/src/App.js
import React from 'react';
import { Button } from 'shared-ui'; // Import from shared package in Monorepo
import './App.css'; // Default Create React App CSS

function App() { 
const handleClick = () => { 
alert('Button clicked!'); 
}; 

return( 
<div className="App"> 
<header className="App-header"> 
<h1>Monorepo Demo with Shared UI</h1> 
<Button onClick={handleClick} variant="primary"> 
ClickMe! 
</button> 
<br /> 
<Button onClick={() => alert('Secondary button clicked!')} variant="secondary"> 
Secondary Button 
</Button> 
</header> 
</div> 
);
}

export defaultApp;
```

Installation and Run Steps:

1. Go to the Monorepo Root Directory: `cd my-monorepo`
2. Install Dependencies: `yarn install` (Yarn will detect the `workspaces` feature and manage dependencies for all packages).
3. Create the Shared UI Package: `yarn workspace shared-ui build` (This creates the `dist` folder of the `shared-ui` package so `web-app` can import it).
4. Start the Web Application: `yarn workspace web-app start` (This command runs the `start` script of the `web-app` package and typically starts the application at `http://localhost:3000`). `web-app` directly installs `shared-ui` in `node_modules`