Environmental requirements

  • yarn v1.x
  • Node. Js > = v10.12.0
  • lerna 3.x

What is Monorepo?

Monorepo is a method of managing the source code of multiple projects in the same repository. The opposite of Monorepo is Multirepo, whose idea is to divide warehouses into modules. There are many popular open source projects using monorepo to manage code, such as Babel and Vue3.0.

The pros and cons of Monorepo

Advantages:

  • Code reuse is easier;
  • Streamlined dependency management, removing repeated dependencies of multiple packages;
  • Convenient large-scale refactoring, can simultaneously refactor multiple packages and unified release, avoid different package management problems;
  • It’s easier to work across teams. When you work across teams, you can work together by simply submitting code instead of publishing to a package manager.
  • Unified management of Lint, Test, build, and Release;
  • Unified place to deal with issues;
  • This facilitates the unified generation of ChangeLog.

Disadvantages:

  • Loss of version information. Monorepo, which releases a single version, will lose the version information of each project, although it is possible to release a separate version.
  • Lack of package-specific access control (Git), where developers must be given access to the entire repository if they want to access a project, which may be a security issue.
  • More hardware consumption: When you only need to develop a project, you have to download the entire repository code, which takes up more network and local storage space.

How to implement Monorepo?

The mainstream solution is to use Yarn Workspaces + LERna.

yarn workspaces

Yarn workspaces can integrate node_modules of multiple packages into one. You only need to run Yarn install to install all package dependencies.

Here’s an example:

root/
  workspace-a/
    package.json
  workspace-b/
    package.json
  node_modules/
  package.json
Copy the code

Workspaces are declared in the root package.json file:

{
  "private": true."workspaces": ["workspace-a"."workspace-b"]}Copy the code

Note that adding private: true prevents the workspace root directory from being published to NPM. Workspaces are an array containing the paths of all “workspaces”. Wildcards such as “workspaces”: [“packages/*”] are also supported.

Package. json for workspace-a and workspace B are as follows:

workspace-a/package.json:

{
  "name": "workspace-a"."version": "1.0.0"."dependencies": {
    "cross-env": "5.0.5"}}Copy the code

workspace-b/package.json:

{
  "name": "workspace-b"."version": "1.0.0"."dependencies": {
    "cross-env": "5.0.5"."workspace-a": "1.0.0"}}Copy the code

Finally, run yarn install in the root directory to install all dependencies. After the installation, a directory structure similar to the following is displayed:

/package.json
/yarn.lock

/node_modules
/node_modules/cross-env
/node_modules/workspace-a -> /workspace-a

/workspace-a/package.json
/workspace-b/package.json
Copy the code

Workspace -b relies on workspace-a and will refer directly to files within the current project, rather than from NPM. There will be no node_modules/, but node_modules in the root directory.

lerna

A tool for managing JavaScript projects with multiple packages. A tool for managing JS projects with multiple packages.

Above is lerNA’s official introduction. Lerna is used to manage multiple packages, optimize the workflow of maintaining multiple packages, and solve the problem of multiple packages being interdependent and published. It is currently used by many well-known open source projects, such as Babel, create-React-app, mint-UI, and React-Router.

The structure of a LERNA project is roughly as follows:

lerna-repo/
  packages/
    package-1/
      package.json
    package-2/
      package.json
  package.json
  lerna.json
Copy the code

The packages/ directory holds all packages. Lerna. json is its configuration file, described later.

How does Lerna work

Lerna management package has two modes: fixed and Independent.

Fixed/Locked Mode This is the default mode. All packages in Fixed mode share a version number. This version number is stored in the version field of lerna.json. So when you run lerna Publish, the modified packages are automatically updated with the version in package.json and published to NPM, while the unmodified packages are not updated. Another issue worth noting is that when the lerna.json version changes the major version number, all packages are updated and released.

Note: If you have a major version number of 0, all changes will be considered breaking, which means a big change that is not backward compatible, which will result in all package versions being updated.

Independent mode Lerna init — Independent is used to initialize a project in Independent mode. You can also manually change the version in lerna.

Independent mode allows each package to update its own version number, so when you run Lerna Publish, you need to select the version of each package that has changed.

Lerna Common commands

lerna init

Create a new lerNA repository or update an existing repository to a new version of LERNA, where the independent/-i option is used to generate independent mode projects.

lerna bootstrap

This command does several things:

  1. NPM install installs dependencies for all packages.
  2. Create soft links for packages that depend on each other.
  3. In all bootstrap packages (not includedcommand.bootstrap.ignorePackage ignored in)npm run prepublish(If an argument is passed--ignore-prepublishThis step will be skipped).
  4. In all bootstrap packages (not includedcommand.bootstrap.ignorePackage ignored in)npm run prepare.

lerna publish

Publish all modified packages, prompt to select a new version, and update all changes to Git and NPM.

lerna run [script]

Execute specific NPM scripts in all packages.

lerna ls

Lists all public packages in the current repository. Packages that are private: true are not listed.

lerna.json

The content of lerna.json is roughly as follows

{
  "version": 1.1.3 ""."npmClient": "npm"."command": {
    "publish": {
      "ignoreChanges": ["ignored-file"."*.md"]."message": "chore(release): publish"."registry": "https://npm.pkg.github.com"
    },
    "bootstrap": {
      "ignore": "component-*"."npmClientArgs": ["--no-package-lock"]}},"packages": ["packages/*"]}Copy the code
  • version: The version of the current repository.
  • npmClient: NPM client. The default value is NPM and the optional value is yarn.
  • command.publish.ignoreChanges: is an array. Changes to files in this array do not trigger version updates.
  • command.publish.message: Custom Git commit information when a new version is released.
  • command.publish.registry: Sets the private repository, which is published to by defaultnpmjs.org.
  • command.bootstrap.ignore: Directories set here will not participatelerna bootstrap.
  • command.bootstrap.npmClientArgs: performlerna bootstrapWill pass all the values of the array as argumentsnpm install.
  • command.bootstrap.scope: limiting thelerna bootstrapIn which packages it works.
  • packages: specifies the path of all packages.

The project practice

Set up

Open Yarn Workspaces:

yarn config set workspaces-experimental true
Copy the code

Create a project:

mkdir lerna-demo && cd lerna-demo
yarn init
Copy the code

Install lerNA globally:

npm install --global lerna
Copy the code

Lerna initialization:

lerna init
Copy the code

The following files are generated in the current directory:

lerna-demo/
  packages/
  package.json
  lerna.json
Copy the code

Configure lerna.json in the root directory to use the YARN client and use workspaces:

/ / lerna. Json {" packages ": [" packages / *"], "version" : "0.0.0",+ "npmClient": "yarn",
+ "useWorkspaces": true
}
Copy the code

Package. json set private to true to prevent the root directory from being published to NPM, and also set workspaces:

// package.json
{
  "name": "lerna-demo",
+ "private": true,
+ "workspaces": [
+ "packages/*"
+]
}
Copy the code

The new package

New packages need to be created under packages/ :

cd packages
mkdir wdm-lerna-demo-core && cd wdm-lerna-demo-core
Copy the code

Use yarn to initialize:

yarn init
Copy the code

The initial version of the new package should be 0.0.0, since it is updated with LERNA, and will be added on top of that when released.

Similarly, create the wdm-lerna-demo-ui package, and the final directory structure is roughly as follows:

lerna-demo/
  packages/
    wdm-lerna-demo-core/
      package.json
    wdm-lerna-demo-ui/
      package.json
  package.json
  lerna.json
Copy the code

Installing common dependencies

If it is all inclusive dependencies, it can be installed like this:

lerna add lodash
Copy the code

Add the dependencies to the dependencies directory in the dependencies directory. Add the dependencies to the dependencies directory in the dependencies directory.

yarn add eslint --dev -W
Copy the code

The -w option explicitly indicates that the yarn operation is performed in the root directory of the workspace, avoiding misoperation of yarn in the root directory.

Install local package dependencies

In this example we set the UI to depend on core:

lerna add wdm-lerna-demo-core --scope=wdm-lerna-demo-ui
Copy the code

Wdm-lerna-demo-ui adds new dependencies:

// package.json
{
  "name": "wdm-lerna-demo-ui"."version": "1.0.0"."main": "index.js"."license": "MIT"."dependencies": {
    "wdm-lerna-demo-core": "^ 1.0.0"}}Copy the code

Then you can use core in your UI:

import myCore from 'wdm-lerna-demo-core'
Copy the code

This is done via a soft link to the wdm-lerna-demo-core/ directory, rather than using a package downloaded from NPM. So, changes in core can be reflected in the UI in real time.

Remove reliance on

If you want to remove a common package that all packages depend on, do this:

lerna exec -- yarn remove lodash
# lerna exec -- yarn remove lodash -- netword-timeout =1000000 # Use this command if a message is displayed indicating that there is a network problem
Copy the code

Lerna exec — [..args] indicates that the command is executed in all packages.

Published to the NPM

First check to see if you are logged in to NPM:

# Print out the user name to indicate that you are logged in
npm whoami
Copy the code

If you have not logged in, run the following command as prompted:

npm login
Copy the code

After login, you can publish:

lerna publish
Copy the code

Here lerna Publish does a few things:

  • Gives you a choice of how to update the version, whether it’s major, minor or beta.
  • Update the version to the changed packagepackage.jsonversion.
  • If some packages depend on the newly updated package, it will be updated automaticallydependenciesVersion number of.
  • Commit your changes to Git and generate a Git commit and tag with the version number.
  • Publish the changed and public package to NPM.

So far, a LERNA project has been set up. See Lerna-demo for the source code.