Lerna

一个用于管理具有多个程序包的 JavaScript 项目的工具。(A tool for managing JavaScript projects with multiple packages.)

Github stars Tracking Chart

一个用于管理多个包的 JavaScript 项目的工具。

关于

将大型代码库拆分为独立版本的软件包对于代码共享非常有用。 但是,在许多存储库中进行更改很麻烦且难以跟踪,跨存储库的测试变得非常复杂。

为了解决这些(以及许多其他问题),一些项目将它们的代码库分成多个软件包存储库(有时称为 monorepos )中。诸如 Babel React Angular Ember Meteor Jest 等项目都在一个单独的存储库中开发它们的所有包。

Lerna 是一个使用 git 和 npm 优化多包存储库管理工作流的工具

Lerna 还可以减少开发和构建环境中大量软件包副本的时间和空间需求 -- 这通常是将项目划分为多个单独的 NPM 软件包的缺点。 有关详细信息,请参阅 hoist 文档了解详情。

Lerna 库看起来像什么?

实际上它很少。你有一个如下所示的文件系统:

my-lerna-repo/
  package.json
  packages/
    package-1/
      package.json
    package-2/
      package.json

Lerna 能做什么?

Lerna 中的两个主要命令是 lerna bootstrap 和 lerna publish 。

bootstrap 会将repo中的依赖链接在一起。publish 将帮助发布任何更新的软件包。

入门

以下说明适用于Lerna 3.x. 我们建议使用它而不是2.x来创建一个新的Lerna项目。如果您需要查看1.x自述文件,请查看 wiki

我们首先以 npm 安装Lerna。

  $ npm install --global lerna

接下来我们将创建一个新文件夹:

$ mkdir lerna-repo && cd $_
$ npx lerna init

这将创建一个 lerna.json 配置文件以及一个 packages 文件夹,因此您的文件夹应该如下所示:

lerna-repo/
  packages/
  package.json
  lerna.json

它如何工作

Lerna 允许您使用以下两种模式之一管理项目:固定或独立。

固定/锁定模式(默认)

固定模式 Lerna 项目在单一版本上运行。版本保存在 version 键下的项目根目录下的 lerna.json 文件中。当您运行 lerna publish 时,如果一个模块自上次发布以来已更新,它将更新为您要发布的新版本。这意味着您只需在需要时发布新版本的软件包。

这是 Babel 目前使用的模式。如果您想自动将所有软件包版本捆绑在一起,请使用此选项这种方法的一个问题是,任何软件包的重大更改都会导致所有软件包都有一个新的主要版本。

独立模式(lerna init - independent )

独立模式Lerna项目允许维护人员相互独立增加包版本。每次发布时,您都会得到一个提示,指出每个已更改的软件包,以指明它是否为修补程序,次要,主要或自定义更改。

独立模式允许您更具体地更新每个软件包的版本,并对一组组件有意义。将这种模式与语义释放之类的东西结合起来可以减少痛苦。 ( atlassian/lerna-semantic-release 中已经有这方面的工作。)

lerna.json 中的 version 键在独立模式下被忽略。

故障排除

如果您在使用 Lerna 时遇到任何问题,请查看我们的疑难排解 记录你可能找到问题答案的地方。

常见问题

请参阅 FAQ.md

(The first version translated by vz on 2020.07.26)

Overview

Name With Ownerlerna/lerna
Primary LanguageTypeScript
Program languageJavaScript (Language Count: 5)
PlatformLinux, Mac, Windows
License:MIT License
Release Count248
Last Release Namev8.1.3 (Posted on 2024-05-13 12:38:17)
First Release Namev1.0.1 (Posted on 2015-12-04 23:25:21)
Created At2015-12-04 09:36:55
Pushed At2024-05-13 08:38:20
Last Commit At
Stargazers Count35.4k
Watchers Count252
Fork Count2.2k
Commits Count2.8k
Has Issues Enabled
Issues Count2578
Issue Open Count348
Pull Requests Count946
Pull Requests Open Count5
Pull Requests Close Count370
Has Wiki Enabled
Is Archived
Is Fork
Is Locked
Is Mirror
Is Private

About

Splitting up large codebases into separate independently versioned packages
is extremely useful for code sharing. However, making changes across many
repositories is messy and difficult to track, and testing across repositories
gets complicated really fast.

To solve these (and many other) problems, some projects will organize their
codebases into multi-package repositories (sometimes called monorepos). Projects like Babel, React, Angular,
Ember, Meteor, Jest, and many others develop all of their packages within a
single repository.

Lerna is a tool that optimizes the workflow around managing multi-package
repositories with git and npm.

Lerna can also reduce the time and space requirements for numerous
copies of packages in development and build environments - normally a
downside of dividing a project into many separate NPM packages. See the
hoist documentation for details.

What does a Lerna repo look like?

There's actually very little to it. You have a file structure that looks like this:

my-lerna-repo/
  package.json
  packages/
    package-1/
      package.json
    package-2/
      package.json

What can Lerna do?

The two primary commands in Lerna are lerna bootstrap and lerna publish.

bootstrap will link dependencies in the repo together.
publish will help publish any updated packages.

What can't Lerna do?

Lerna is not a deployment tool for serverless monorepos. Hoisting might be incompatible with traditional serverless monorepo deployment techniques.

Getting Started

The instructions below are for Lerna 3.x.
We recommend using it instead of 2.x for a new Lerna project.

Let's start by installing Lerna as a dev dependency of your project with npm.

$ mkdir lerna-repo && cd $_
$ npx lerna init

This will create a lerna.json configuration file as well as a packages folder, so your folder should now look like this:

lerna-repo/
  packages/
  package.json
  lerna.json

How It Works

Lerna allows you to manage your project using one of two modes: Fixed or Independent.

Fixed/Locked mode (default)

Fixed mode Lerna projects operate on a single version line. The version is kept in the lerna.json file at the root of your project under the version key. When you run lerna publish, if a module has been updated since the last time a release was made, it will be updated to the new version you're releasing. This means that you only publish a new version of a package when you need to.

This is the mode that Babel is currently using. Use this if you want to automatically tie all package versions together. One issue with this approach is that a major change in any package will result in all packages having a new major version.

Independent mode

lerna init --independent

Independent mode Lerna projects allows maintainers to increment package versions independently of each other. Each time you publish, you will get a prompt for each package that has changed to specify if it's a patch, minor, major or custom change.

Independent mode allows you to more specifically update versions for each package and makes sense for a group of components. Combining this mode with something like semantic-release would make it less painful. (There is work on this already at atlassian/lerna-semantic-release).

Set the version key in lerna.json to independent to run in independent mode.

Troubleshooting

If you encounter any issues while using Lerna please check out our Troubleshooting
document where you might find the answer to your problem.

Frequently asked questions

See FAQ.md.

Concepts

Lerna will log to a lerna-debug.log file (same as npm-debug.log) when it encounters an error running a command.

Lerna also has support for scoped packages.

Run lerna --help to see all available commands and options.

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/*"]
}
  • version: the current version of the repository.
  • npmClient: an option to specify a specific client to run commands with (this can also be specified on a per command basis). Change to "yarn" to run all commands with yarn. Defaults to "npm".
  • command.publish.ignoreChanges: an array of globs that won't be included in lerna changed/publish. Use this to prevent publishing a new version unnecessarily for changes, such as fixing a README.md typo.
  • command.publish.message: a custom commit message when performing version updates for publication. See @lerna/version for more details.
  • command.publish.registry: use it to set a custom registry url to publish to instead of
    npmjs.org, you must already be authenticated if required.
  • command.bootstrap.ignore: an array of globs that won't be bootstrapped when running the lerna bootstrap command.
  • command.bootstrap.npmClientArgs: array of strings that will be passed as arguments directly to npm install during the lerna bootstrap command.
  • command.bootstrap.scope: an array of globs that restricts which packages will be bootstrapped when running the lerna bootstrap command.
  • packages: Array of globs to use as package locations.

The packages config in lerna.json is a list of globs that match directories containing a package.json, which is how lerna recognizes "leaf" packages (vs the "root" package.json, which is intended to manage the dev dependencies and scripts for the entire repo).

By default, lerna initializes the packages list as ["packages/*"], but you can also use another directory such as ["modules/*"], or ["package1", "package2"]. The globs defined are relative to the directory that lerna.json lives in, which is usually the repository root. The only restriction is that you can't directly nest package locations, but this is a restriction shared by "normal" npm packages as well.

For example, ["packages/*", "src/**"] matches this tree:

packages/
├── foo-pkg
│   └── package.json
├── bar-pkg
│   └── package.json
├── baz-pkg
│   └── package.json
└── qux-pkg
    └── package.json
src/
├── admin
│   ├── my-app
│   │   └── package.json
│   ├── stuff
│   │   └── package.json
│   └── things
│       └── package.json
├── profile
│   └── more-things
│       └── package.json
├── property
│   ├── more-stuff
│   │   └── package.json
│   └── other-things
│       └── package.json
└── upload
    └── other-stuff
        └── package.json

Locating leaf packages under packages/* is considered a "best-practice", but is not a requirement for using Lerna.

Legacy Fields

Some lerna.json fields are no longer in use. Those of note include:

Common devDependencies

Most devDependencies can be pulled up to the root of a Lerna repo with lerna link convert

The above command will automatically hoist things and use relative file: specifiers.

Hoisting has a few benefits:

  • All packages use the same version of a given dependency
  • Can keep dependencies at the root up-to-date with an automated tool such as GreenKeeper
  • Dependency installation time is reduced
  • Less storage is needed

Note that devDependencies providing "binary" executables that are used by
npm scripts still need to be installed directly in each package where they're
used.

For example the nsp dependency is necessary in this case for lerna run nsp
(and npm run nsp within the package's directory) to work correctly:

{
  "scripts": {
    "nsp": "nsp"
  },
  "devDependencies": {
    "nsp": "^2.3.3"
  }
}

Git Hosted Dependencies

Lerna allows target versions of local dependent packages to be written as a git remote url with a committish (e.g., #v1.0.0 or #semver:^1.0.0) instead of the normal numeric version range.
This allows packages to be distributed via git repositories when packages must be private and a private npm registry is not desired.

Please note that lerna does not perform the actual splitting of git history into the separate read-only repositories. This is the responsibility of the user. (See this comment for implementation details)

// packages/pkg-1/package.json
{
  name: "pkg-1",
  version: "1.0.0",
  dependencies: {
    "pkg-2": "github:example-user/pkg-2#v1.0.0"
  }
}

// packages/pkg-2/package.json
{
  name: "pkg-2",
  version: "1.0.0"
}

In the example above,

  • lerna bootstrap will properly symlink pkg-2 into pkg-1.
  • lerna publish will update the committish (#v1.0.0) in pkg-1 when pkg-2 changes.

README Badge

Using Lerna? Add a README badge to show it off: lerna

[![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org/)

Wizard

If you prefer some guidance for cli (in case you're about to start using lerna or introducing it to a new team), you might like lerna-wizard. It will lead you through a series of well-defined steps:

lerna-wizard demo image

To the top