一个用于管理具有多个包的JavaScript项目的工具。
关于
将大型代码库拆分为单独的独立版本包对于代码共享非常有用。然而,跨多个存储库进行更改是混乱的,而且很难跟踪,跨存储库的测试也变得非常复杂。
为了解决这些(和许多其他)问题,一些项目将其代码库组织到多包存储库(有时称为monorepos)。像Babel、React、Angular、Ember、Meteor、Jest等项目在一个存储库中开发所有的包。
Lerna是一个工具,它优化了使用git和npm管理多包存储库的工作流。
Lerna还可以减少开发和构建环境中对包的大量副本的时间和空间需求,这通常是将项目划分为多个单独的NPM包的缺点。有关详细信息,请参阅 提升 提升文档。
Lerna repo是什么样子的?
事实上很少有。您的文件结构如下所示:
my-lerna-repo/
package.json
packages/
package-1/
package.json
package-2/
package.json
Lerna能做什么?
Lerna中的两个主要命令是Lerna bootstrap和Lerna publish。
bootstrap将把repo中的依赖项链接在一起。publish将帮助发布任何更新包。
Lerna 不能做什么?
Lerna不是无服务器monorepos的部署工具。提升可能与传统的无服务器monorepo部署技术不兼容。
开始使用
下面的说明适用于Lerna 3.x。我们建议在新的Lerna项目中使用它而不是2.x。
让我们从安装Lerna作为npm项目的开发依赖项开始。
$ mkdir lerna-repo && cd $_
$ npx lerna init
这将创建一个lerna.json配置文件以及packages 文件夹,因此您的文件夹现在应该如下所示:
lerna-repo/
packages/
package.json
lerna.json
工作原理
Lerna允许您使用两种模式之一管理项目:固定模式或独立模式(Fixed or Independent)。
固定/锁定(Fixed/Locked)模式(默认)
固定模式Lerna项目在一个版本行上运行。版本保存项目根目录下lerna.json文件,在version键下。运行lerna publish时,如果某个模块自上次发布以来已更新,则它将更新为您要发布的新版本。这意味着您只在需要时发布包的新版本。
注意:如果您的主版本为0,则所有更新都将被视为中断。因此,使用主版本零运行lerna publish并选择任何非预发布版本号将导致为所有包发布新版本,即使不是所有包自上次发布以来都发生了更改。
这是babel目前使用的模式。如果要自动将所有包版本绑定在一起,请使用此选项。这种方法的一个问题是,任何包中的重大更改都将导致所有包都有一个新的主版本。
独立(Independent) 模式
lerna init --independent
独立模式Lerna项目允许维护人员独立地增加包版本。每次发布时,对于每个已更改的包,都将得到一个提示,以指定它是修补程序、次要更改、主要更改还是自定义更改。
独立模式允许您更具体地更新每个包的版本,并对一组组件有意义。将这种模式与语义释放之类的东西结合在一起,会让它不那么痛苦。(atlassian/lerna semantic release已经对此进行了研究)。
设置version: independent 键lerna.json以独立模式运行。
故障排除
如果您在使用Lerna时遇到任何问题,请查看我们的故障排除文档,您可以从中找到问题的答案。
常见问题解答
见 FAQ.md.
概念
当它在运行命令时遇到错误Lerna会记录到lerna-debug.log文件(与npm-debug.log相同)。
Lerna还支持作用域包。
运行lerna--help查看所有可用的命令和选项。
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: 存储库的当前版本
- npmClient: 用于指定运行命令的特定客户端的选项(也可以按每个命令指定)。更改为“yarn”以使用yarn运行所有命令。默认为“npm”。
- command.publish.ignoreChanges: lerna changed/publish中不包含的globs。使用此选项可防止发布不必要的新版本进行更改,例如修复自README.md
- command.publish.message:为发布执行版本更新时的自定义提交消息。有关详细信息,请参见@lerna/version。
- command.publish.registry: 使用它可以设置要发布到的自定义注册表url,而不是npmjs.org网站,如果需要,您必须已经通过身份验证。
- command.bootstrap.ignore:运行lerna bootstrap命令时不会引导的globs数组。
- command.bootstrap.npmClientArgs:在执行lerna bootstrap命令期间将作为参数直接传递给npm install的字符串数组。
- command.bootstrap.scope:一个globs数组,用于限制在运行lerna bootstrap命令时将引导哪些包。
- packages:要用作包位置的全局数组。
在lerna.json中的packages是一个文件数组匹配包含package.json的目录,这就是lerna如何识别“leaf”包(相对于“root”package.json,用于管理整个repo的dev依赖项和脚本)。
默认情况下,lerna将包列表初始化为[“packages/*”],但您也可以使用其他目录,如[“modules/*”]或[“package1”,“package2”]。定义的glob目录位置是相对于lerna.json,这通常是存储库根。唯一的限制是不能直接嵌套包位置,但这也是“普通”npm包共享的限制。
例如,[“packages/*”,“src/**”]与此树匹配:
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
在packages/*下定位leaf包被认为是“最佳实践”,但不是使用Lerna的要求。
旧字段
一些lerna.json字段不再使用。值得注意的包括:
lerna:最初用来表示lerna的当前版本。使过时并在v3中删除
公共开发依赖性
大多devDependencies 可以通过Lerna link convert被拉到Lerna repo的根目录
上面的命令将自动提升对象并使用相对file: 说明符。
提升有几个好处:
-
所有包都使用给定依赖项的同一版本
-
可以使用诸如GreenKeeper这样的自动化工具在根目录上保持最新的依赖关系
-
减少依赖项安装时间
-
所需存储更少
注意,提供npm脚本使用的“二进制”可执行文件的devDependencies 仍然需要直接安装在使用它们的每个包中。
例如,在这种情况下,要使lerna run nsp(和npm run nsp在包的目录中)正常工作,nsp依赖关系是必需的:
{
"scripts": {
"nsp": "nsp"
},
"devDependencies": {
"nsp": "^2.3.3"
}
}
Git托管的依赖项
Lerna允许将本地依赖包的目标版本写入git远程url,并使用commitish(git 版本标识)(例如,#v1.0.0或#semver:^1.0.0),而不是普通的数字版本范围。当包必须是私有的并且不需要私有的npm注册时,这允许通过git存储库分发包。
请注意,lerna并没有实际将git历史分割到单独的只读存储库中。【解决方案:从monorepo中实现“git-only”分发有多种方式供以后参考。1:splitsh 2:regular git filter-branch --subdirectory-filter packages/】这是用户的责任。(有关实施细节,请参阅此注释)
// 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"
}
在上面的例子中,
-
llerna bootstrap将正确地将pkg-2符号链接到pkg-1。
-
当pkg-2发生变化时,lerna publish将更新pkg-1中的commitish(#v1.0.0)。