background

When developing a large project, a business Project1 relies on lib1, lib2, and lib3, which in turn depends on lib1, which in turn depends on lib1 and lib2. Lib1,lib2,lib3 are NPM packages developed and maintained by ourselves. They are distributed to private servers respectively.

How to organize and manage these dependency packages is a problem

(Multirepo) Multiple dependencies are managed by Git independently. The problem is also very clear. If there are changes in each library, you need to publish them online and then install them to use them. If you are in a development environment, local packaging becomes more complex, and the more complex the dependencies become, the more difficult it is to maintain.

Mode 2: (Monorepo) Conversely, if all the dependent libraries are completely put into a project, it is not easy to reuse and share common code.

lerna

A tool for managing JavaScript projects with multiple packages.

Lerna official website: lerna.js.org/ Lerna Documentation: github.com/lerna/lerna…

Star repositories currently using LerNA for multi-packages management are:

  • babel/babel
  • facebook/create-react-app
  • vuejs/vue-cli
  • webpack/webpack-cli

The library file structure managed by LERNA is as follows:

lerna-usage/
  package.json
  packages/
    package- 1/
      package.json
    package2 -/
      package.json
Copy the code

Lerna is used to split projects or modules into packages and manage them in a Git repository.

  • Through the commandlerna boostrapAutomatically resolve dependencies between packages, and dependencies within packages are linked directly to each other using symlink.
  • Through the commandlerna publishRely ongitDetect file changes, automatically publish and manage version numbers.
  • Based on git submission records, Changelog is automatically generated

Management mode

Lerna has two management modes, fixed mode and independent mode

Fixed/Locked mode (default)

Command: lerna init Fixed mode unified versioning using versions in lerna.json This pattern automatically bundles all packages package versions together, and significant changes to any one or more packages will result in upgrades to all packages version numbers.

Stand-alone mode

Command: lerna init –independent

In independent mode, init requires the option –independent. This pattern allows consumers to change the version number individually for each package. When lerna publish is executed each time, the version number to be upgraded will be asked one by one for all packages that have been updated. The base version is the version number in its package.json. In this case, the version number of lerna.json does not change and defaults to independent.

lerna.json

{
  "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

Parameter Description:

  • versionVersion number of the current library. In standalone mode, this parameter is set toindependent
  • npmClientAllows you to specify the client used by the command. The default isnpm, can be set toyarn
  • command.publish.ignoreChangesYou can specify which directory or file changes will not be published
  • command.publish.messageSpecifies the format of the message to submit at publication time
  • command.publish.registrySet the registered address for NPM package publishing
  • command.bootstrap.ignoreSet executelerna bootstrapPackages that are unaffected when installing dependencies
  • command.bootstrap.npmClientArgsSpecify in executionlerna bootstrapCommand is passed tonpm installThe parameters of the
  • command.bootstrap.scopeSpecify which packages are affected by the lerna bootstrap command
  • packagesSpecify the directory where the package resides

use

There are three packages assumed below:

  • Feu-app emulates business master projects, does not need to publish NPM packages, and relies on FEU-UI and FeU-Tools
  • Feu-ui emulates the UI library project, does not need to publish NPM packages and relies on FEU-Tools
  • Feu-tools Simulates the shared library of tools. NPM packages must be published

Suppose the interdependence is as follows:

1. Install LERNA globally

$ npm install --global lerna
Copy the code

2, use,git initInitialize a project repository

$ git init lerna-usage && cd lerna-usage
Copy the code

3. Initialize lerNA

$ lerna init
Copy the code

The default fixed mode is used here. Currently the entire folder directory looks like this:

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

Create three new packages (FEU-app, FEu-UI, feu-tools)

$ lerna create feu-app && lerna create feu-ui && lerna create feu-tools
Copy the code

After executing the above code, the entire document directory results as follows:

5. Add dependencies and code

feu-tools

Add the following code to packages/feu-tools/lib/tools.js:

'use strict';

function add(a, b) {
	console.log("Tools library, call function add, input: %d, %d",a ,b)
    return a + b;
}
function min(a, b) {
	console.log("Tools library, call function min, input: %d, %d",a ,b)
    return Math.min(a, b);
}

module.exports = { add, min };
Copy the code

feu-ui

Step 1: To prevent it from being published to NPM, we set “private”=true in its package.json.

Step 2: Add the third-party dependency package “Chalk” to feU-UI’s development dependency library and run the following command:

$ lerna add chalk --scope=feu-ui --dev
Copy the code

Step 3 Add the local feU-tools package to the feU-UI dependency library and run the following command:

$ lerna add feu-tools --scope=feu-ui
Copy the code

When local packages are added, lerna commands are associated with them via symlink, creating a shortcut that is very useful for local development.

Step 4 Add the following code to packages/feu-ui/lib/ui.js:

'use strict';

const chalk = require('chalk');
const { add } = require('feu-tools');

function ui(result) {
    console.log("UI library, result parameter :", result);
    console.log(chalk.red("UI library, result:"+chalk.blue(add(result, 10))));
}

module.exports = ui;
Copy the code

feu-app

Step 1 To prevent it from being published to NPM, we set “private”=true in its package.json.

Step 2: Add the local feU-tools package to the feu-app dependency library and run the following command:

$ lerna add feu-tools --scope=feu-app
Copy the code

Step 3 Add the local package feu-ui to the dependency library of feu-app and run the following command:

$ lerna add feu-ui --scope=feu-app
Copy the code

Step 4 Add the following code to packages/feu-app/lib/app.js:

'use strict';

const { min } = require('feu-tools');
const ui = require("feu-ui");

function app() {
    console.log("App Main entrance");
    let minNum = min(2.5);
    ui(minNum);
}

app();
Copy the code

6. Operation effect

Since all dependency packages have been installed, there is no need to execute lerna Bootstrap. If it is a new Clone existing LERna project, you can run the lerna bootstrap command to install all packages dependencies in one click. Run the following command:

$ cd packages/feu-app && node lib/app.js
Copy the code

The running results are as follows:

You can see that the calls between the three packages and between third-party dependent libraries have executed successfully. The above process shows the whole process of using LerNA completely. If there is no requirement to publish and share with other teams, it can be ended here. If we also wanted to share FeU-Tools with other teams and individuals, we would also need to publish this package as an NPM package.

Published to the NPM

precondition

  • If it’s a pre-compiled project, you might need to pass itlerna run buildperformbuildCommand generation packaging.
  • Before you release, you need to make sure that the relevant code has been committed to Git.
  • throughlerna changedView what updated packages are available.
  • Make sure your NPM account is already logged in, otherwise the post may fail.
  • Make sure you have permission to distribute the NPM package you want to distribute.
  • inlerna.jsonSet up the correct NPM Registry, for examplehttps://registry.npmjs.org/.

Execute issue command

When everything is ready, you can execute the following command:

$ lerna publish
Copy the code

The problem may vary according to the management mode we choose. Since we chose fixed schema, the version numbers of all packages are updated according to the version numbers in lerna.json. The interface for asking the version number is as follows:

The next screen after selecting the version number is as follows:

We can see that the version numbers of the three packages are all upgraded to 0.1.2, and we can see that feU-app and FEU-UI are shown as private, indicating that they will not be released to NPM.

The execution result

You can see that the publication is successful.

Common commands

lerna init

Initialize a Lerna project fixed mode (default) : Lerna init Independent mode: Lerna init —-independent

lerna bootstrap

Install all packages dependencies and connect cross-dependencies for local packages.

lerna import

Example 1: ** Import the packages with path ~/Users/Product into the packages named Utilites.

$ lerna import ~/Users/Product --dest=utilities
Copy the code

lerna add

Add local or remote packages as dependencies to the current packages, one at a time. Example 1: Add remote dependency package “chalk” to feU-UI’s development dependency library and run the following command:

$ lerna add chalk --scope=feu-ui --dev
Copy the code

Case 2: Add the local feu-tools package to the feu-app dependency library and run the following command:

$ lerna add feu-tools --scope=feu-app
Copy the code

lerna create

Create a lerNA managed package

Case 1:

$ lerna create feu-tools
Copy the code

lerna clean

Delete the node_modules directory under all packages, or you can delete the node_modules directory under the specified package. Note: dependency definitions in package.json and node_modules in the root directory are not removed.

Case 1: Delete only the node_modules directory under the feU-UI package

$ lerna clean --scope=feu-ui
Copy the code

lerna ls

List all public packages (excluding private=true)

lerna changed

Check which packages have been updated since the last release.

lerna diff

View git diff changes for all packages or specified packages since the last release.

lerna run

NPM script script commands are executed within each package that contains the script command, or can be specified to be executed under a package.

Case 1: Execute the build script command in the FEU-UI package

$ lerna run build --scope=feu-ui
Copy the code

lerna exec

Execute any command in each package or specify that it be executed under a package. Case 1:

$ lerna exec -- npm view \$LERNA_PACKAGE_NAME
Copy the code

lerna link

Symlink all interdependent packages together.

lerna version

Version iteration. Executing this command does these things:

  • Identifies packages that depend on updates since the last tag version.
  • Prompt for a new version.
  • Modify the package metadata to reflect the new release and run the appropriate lifecycle scripts in the root directory and in each package.
  • Commit these changes and mark the commit.
  • Push to git remote.

Version Update principles:

  • Feat submission exists: The minor version needs to be updated
  • Fix submission exists: Patch version needs to be updated
  • There is a BREAKING CHANGE commit: need to update a large version

lerna publish

Publish the package that needs to be published. This command can either contain lerna version work or simply publish the package.

Behavior varies depending on the management model. Refer to the management Mode section. Note: Packages marked private (private=true in package.json) will not be published.

lerna publish

Release packages that have been updated since the last release, containing lerna version work.

lerna publish from-git

Displays the package that publishes the markup in the current commit, similar to executing lerna version independently and then executing this command to publish.

lerna publish from-package

Displays the latest version of the package that does not exist in the publish NPM Registry.

Other matters

Package publishing issues starting with @

If the name of a publish package starts with @, such as @feu/tools, NPM defaults to a private publish and uses NPM publish –access public. Lerna publish does not support this parameter. For the solution, see issues

Scheme reference:

// package.json { "name": "@feu/tools", "publishConfig": { "access": "Publish" // If the module needs to publish, the scope module needs to publish, otherwise permission validation is required}}Copy the code

Solution after lerna release failure

You can publish from-git with Lerna after your failure starting with the results of the last release iteration. Reference: github.com/huruji/blog…

Configure yarn useWorkspaces

Lerna bootstrap –npm-client yarn –use-workspaces or lerna.json:

// lerna.json
{
  "packages": ["packages/*"].// Configure the package directory
  "npmClient": "yarn"."useWorkspaces": true // Use YARN workspaces
}
Copy the code

Execute commands in topology order

$ lerna run --stream --sort build
Copy the code

But these Commits to support

Lerna version and Changelog generation of LERNA depend on Conventional Commits. You need to ensure that the COMMIT MSG complies with the specification.

Related documents:

  • www.conventionalcommits.org/en/v1.0.0/
  • Juejin. Cn/post / 684490…

The demo project

Demo project download address