What is Monorepo

Monorepo is a way to manage project code by managing multiple modules/packages in a project repository (REPO), as opposed to the usual repO for each module.

├ ─ ─ packages | | ├ ─ ─ two packages pkg1 | | | ├ ─ ─ package. The json | | ├ ─ ─ pkg2 | | | ├ ─ ─ package. The json ├ ─ ─ package. The jsonCopy the code

Implement a simple JS Monorepo project using Yarn Workspaces

Create a project directory

Create a folder called monorepo

mkdir monorepo
Copy the code

Initialize the project

Initialize YARN in the monorepo directory

yarn init
Copy the code

The package.json file should appear in the monorepo directory

Configuration Yarn machine-specific

Modify the code in the /monorepo/package.json file as follows

{
  "name": "monorepo"."version": "1.0.0"."license": "MIT"."private": true."workspaces":  [
      "packages/*"],}Copy the code

Private :true: defines this project as a private project. When using yarn Workspace, you must always set the private property to true.

Workspaces: Defines the location of each package. In this project, we will place each package in the Packages directory. Note that this property is an array of strings, and we can add as many bits as our project needs.

Create packages directory

Create the Packages folder under the Monorepo directory to hold our packages

mkdir packages
Copy the code

Initialize the package – a

In /monorepo/ Packages /, create folder package-a and initialize YARN

cd packages
mkdir package-a
cd package-a
yarn init
Copy the code

We can follow the monorepo naming convention and name it @monorepo/package-a in package.json

The development package – a

At this point, we are ready to start developing Package-A.

As a demonstration, we can create a new main.js file under package-a and add the following code

// index.js
console.log("This is a package - a");
Copy the code

Initializes the package – b

Create folder package-b under /monorepo/ Packages/and yarn is initialized. Step with the package – a

The development package – b

At this point, we are ready to start development on Package-B.

As a demonstration, we can create a new main.js file under package-b and add the following code

// index.js
console.log("This is a package - b");
Copy the code

Reference package-a in package-b

A big advantage of Monorepo is that different packages under the same Monorepo project can refer to each other.

Suppose we have three React apps under our Monorepo project. Each React App requires the same line chart component. At this point we can:

  • Each React App develops its own line chart component. This, however, creates duplication of effort, and in the future three line chart components will be maintained simultaneously.
  • Develop a line chart component in one React app, and then copy it in the other two React apps. This eliminates repetitive development, but three React App line chart components still need to be maintained when the line chart components need to be changed.
  • Create a line chart package and reference it in the three React Apps. Thus, we only need to develop and maintain the line chart Package.

At first, we need/monorepo/packages/package – b/package. Add dependent package – a json.

{
  "name": "@monorepo/package-b"."version": "1.0.0"."main": "index.js"."license": "MIT"."scripts": {
    "dev": "node index.js"
  },
  "dependencies": {
    "@monorepo/package-a": "1.0.0"}}Copy the code

Then in/monorepo/packages/package – b/index. Js refer package – a

// index.js
require("@monorepo/package-a");
console.log("This is package-b");

Copy the code

Note that running index.js under package-b will cause an error because package-a is not installed yet, although we reference it in dependencies. Therefore, we need to run YARN or YARN Install.

At this point, we run the index.js file under package-b again, and we see the following output

$ node index.js
This is package-a
This is package-b
Copy the code

Introduce TS and React

Let’s introduce TS and React in the Monorepo project

Create the React App

In the /monorepo/ Packages directory, execute

yarn create react-app client --template typescript
Copy the code

Then, you can go to the client directory and start react to verify that the installation is successful

cd client
yarn start
Copy the code

Create Interface package

Assuming we do full stack development with TS, a common requirement is that the interfaces of the front and back apis should be shared.

So here we create a package to share the interface

First, we create a new folder interface under the /monorepo/ Packages/directory

mkdir interface
Copy the code

Next, we initialize the YARN project yarn Init under interface

Next, we initialize the TS project TSC –init

Json “declaration”: true “outDir”: “./dist” “rootDir”: “./ SRC”

Finally, we modify the package.json file as follows

{
  "name": "@monorepo/interface"."version": "1.0.0"."main": "dist/index.js"."types": "dist/index.d.ts"."license": "MIT"."scripts": {
    "build": "tsc"}}Copy the code

The development of interface package

Under the interface directory, we can create the SRC directory and create index.ts under the SRC directory

Declare an interface in index.ts

// index.ts
export interface MyAPIResponse{
    msg: string
}
Copy the code

At this point, we convert the TS code into JS code YARN Build in the interface directory

We can see a new dist folder in the Interface directory to save our built JS files.

Reference the Interface Package in the React project

Add dependencies to package.json in the React project

"@ monorepo/interface" : "1.0.0"Copy the code

The installation depends on YARN or YARN Install

This way we can reference the interface defined in the Interface Package in the React project. As in the SRC/App. The TSX

import { MyAPIResponse } from "@monorepo/interface";
Copy the code

Noreactive and global Package

nohoisting

All dependencies in monorepo are stored in node_modules at the root: /monorepo/node_modules

But in some cases, we may need different versions of the same package. For example, a React project is older and uses Bootstrap 4. Another new project in development decided to use Bootstrap 5.

At this point we need to modify the package.json file in the root directory

{
  "name": "monorepo"."version": "1.0.0"."license": "MIT"."private": true."workspaces": {
    "packages": [
      "packages/*"]."nohoist": [
      "**/bootstrap"]}}Copy the code

As you can see, our workspaces has a new nohoist property, where we can add the names of packages that do not need to be shared.

Install global Package

Prettier can be installed in the root directory of a project where prettier is needed to format code

yarn add prettier -W
Copy the code

Here we use W flag to have yarn Workspace install dependencies in the root directory.

conclusion

This article introduces some basic concepts and implementation methods of YARN Workspaces MonorePO.

In practical work, lerna and other tools can be combined to build our MonorePO project.