Monorepo is a software development strategy where multiple projects are managed in a single code repository. In this strategy, each project has its own folder or package, but all code resides in a single repository. Monorepo can be a powerful tool for managing large and complex codebases.
Advantages of monoreponement:
- Reduces repetition: Because code used in multiple projects is kept in one place, code duplication is reduced. This makes the code base more consistent and easier to maintain.
- Increases productivity: Monorepo makes it easier for development teams to make changes to the codebase and add new features. Using a single repository makes things like code reviews and merges simpler.
- Accelerates development: Monorepo ensures that changes to the codebase are instantly reflected across all projects. This speeds up the development cycle and enables faster deliveries.
Disadvantages of Monorepon:
- Complexity: Monorepo can be a more complex structure for large and complex codebases. This can make it difficult to navigate and debug the codebase.
- Performance: Monorepo may require more storage and processing power for large codebases.
- Training: Monorepo may require development teams to learn a new way of working.
JavaScript Libraries for Using Monorepo:
Many JavaScript libraries are available to facilitate development with Monorepo. Some of the most popular libraries are:
- Lerna: A JavaScript library that makes developing with Monorepo easier. Lerna helps automate things like package management, task execution and version control.
- Yarn: JavaScript package manager. It has many features that make developing with Monorepo easier.
- Nx: It is a tool for developing applications with various technologies such as Angular and React. Nx supports monorepo builds and allows you to manage multiple projects or libraries in a single repository. It also offers various features to facilitate the development process.
- Rush: It is a monorepository management tool developed by Microsoft. It has many features similar to Lerna.
Monorepo can be a powerful tool for managing large and complex codebases. If you are considering using Monorepo, it is important to first carefully evaluate the advantages and disadvantages of this strategy.
Let’s make a simple monorepo project using Lerna and React JS.
1. First, install Lerna:
npm install -g lerna
2. Next, create a home folder and go into it:
mkdir monorepo-example
cd monorepo-example
3. Command to install monorepo with Lerna:
lerna init
Let’s have two packages, “common” and “sample-app”. Our scenario is to use the modal component in the common package in the sample-app application.
4. Let’s create a folder packages and inside it create a folder common and a folder sample-app:
mkdir packages
cd packages
mkdir common
mkdir sample-app
5. Let’s go inside each package and create React applications:
cd packages/common
npx create-react-app .
cd ../sample-app
npx create-react-app .
6. To add the dependency between sample-app and common, let’s give the common package as a dependency of the sample-app package:
package.json
...
"dependencies": {
"common": "file:../common/src/components/modal"
},
...
7. Then run the yarn command to install the package:
yarn
8. Let’s add the Modal component in the sample-app package:
App.js
import Modal from "common/src/components/modal/Modal";
const App = () => {
return (
<div className="App">
<header className="App-header">
<h1>Monorepo Example App</h1>
<Modal/>
</header>
</div>
);
}
export default App;
You may need an additional loader to handle the result of these loaders.
When we stand up the sample-app package, we are likely to get an error like below. So we will need to configure webpack with a package called “craco”. After installing the package, let’s create a craco.config.js file in the main directory and add the following codes.
yarn add -D @craco/craco
const path = require("path");
const { getLoader, loaderByName } = require("@craco/craco");
const packages = [];
packages.push(path.join(__dirname, "../common"));
module.exports = {
webpack: {
configure: (webpackConfig, arg) => {
const { isFound, match } = getLoader(webpackConfig, loaderByName("babel-loader"));
if (isFound) {
const include = Array.isArray(match.loader.include)
? match.loader.include
: [match.loader.include];
match.loader.include = include.concat(packages);
}
return webpackConfig;
},
},
};
You can access the source codes of the sample project from this link. 🔗