Source: jsilvax. A Beginner's Guide to Lerna with Yarn Workspaces. Oct/6/2018node
当结合在一块儿时,Lerna和Yarn Workspaces能够简化和优化对多包仓库的管理。 Lerna 经过提供有用的实用命令来处理跨多个包的任务执行,使版本管理和将包发布到NPM Org中成为一种轻松的体验。 Yarn Workspaces 管理咱们的依赖关系。它不须要多个node_modules目录,而是智能地优化了依赖关系,将他们一并安装,并容许在一个monorepo中交叉连接依赖关系。Yarn Workspaces提供了像Lerna这样的工具来管理多包仓库。git
为了开始,让咱们启用Yarn Workspaces吧github
yarn config set workspaces-experimental true
复制代码
如今咱们能够经过建立一个模拟项目来讲明这些概念了npm
mkdir my-design-system && cd my-design-system
复制代码
而后,咱们初始化项目json
yarn init
复制代码
并将Lerna添加为开发依赖。bootstrap
yarn add lerna --dev
复制代码
而后你会想要初始化Lerna,这将建立一个lerna.json和一个包目录缓存
lerna init
复制代码
为了设置Lerna开启Yarn工做空间,咱们须要配置lerna.json。 让咱们添加yarn做为咱们的npm客户端,并指定咱们使用yarn工做空间。在本教程中,咱们将独立地版本化咱们的包。markdown
// lerna.json
{
"packages": ["packages/*"],
"version": "independent",
"npmClient": "yarn",
"useWorkspaces": true
}
复制代码
此时咱们应该只有一个根 package.json。在这个根 package.json中,咱们须要添加workspaces和private为true。将private设置为true将阻止根项目被发布到NPM。并发
// package.json
{
"name": "my-design-system",
"private": true,
"workspaces": [
"packages/*"
]
}
复制代码
须要在包目录下建立新的包。让咱们建立一个模拟表单包app
cd packages
复制代码
一旦咱们进入了正确的目录,咱们就能够建立并cd到咱们的新包中了
mkdir my-design-system-form && cd my-design-system-form
复制代码
而后咱们经过运行 yarn init 来建立一个新的package.json
yarn init
复制代码
新包的名称应该遵循咱们的NPM Org scope命名方式,例如:@my-scope-name。 一样重要的是,新的包要从0.0.0这样的版本开始,由于一旦咱们使用Lerna进行第一次发布,它就会发布成0.1.0或1.0.0。
// package.json
{
"name": "@my-scope-name/my-design-system-form",
"version" : "0.0.0",
"main" : "index.js"
}
复制代码
若是您有一个支持私有包的NPM Org帐户,您能够在您的模块的独立包.json中添加如下内容。
"publishConfig": {
"access": "restricted"
}
复制代码
如今咱们知道了建立新包的流程,假设说咱们最后的结构是这样的。
my-design-system/
packages/
my-design-system-core/
my-design-system-form/
my-design-system-button/
复制代码
若是咱们想把my-design-system-button做为依赖关系添加到my-design-system-form中,并让Lerna将它们进行符号连接,咱们能够经过cd到该包中来实现。
cd my-design-system-form
复制代码
而后运行如下内容。
lerna add @my-scope-name/design-system-button --scope=@my-scope-name/my-design-system-form
复制代码
这将更新@my-scope-name/my-design-system-form的package.json。 咱们的package.json应该是这样的。
// package.json
{
"name": "@my-scope-name/my-design-system-form",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"@my-scope-name/my-design-system-button": "^1.0.0"
}
}
复制代码
如今,你能够在index.js中引用这个本地依赖关系,如
import Button from '@my-scope-name/my-design-system-button';
复制代码
作法和前面的命令相似。不过这是针对/packages/* 的。无论你要加的依赖是本地的同级依赖仍是来自NPM的依赖,都不要紧。
lerna add the-dep-name
复制代码
若是你有常见的开发依赖,最好在 workspace 的 root package.json中指定。例如,能够是Jest、Husky、Storybook、Eslint、Prettier等依赖项
yarn add husky --dev -W
复制代码
*添加-W标志,就能够明确表示咱们要把依赖关系添加到工做区根目录。
若是有一个全部包都使用的依赖,但你想删除,Lerna有exec命令,能够在每一个包中运行一个任意命令。有了这些知识,咱们就可使用exec来删除全部包的依赖关系。
lerna exec -- yarn remove dep-name
复制代码
Lerna提供了run命令,它将在每一个包含了npm脚本的包中运行该脚本。 例如,假设咱们全部的包都遵循my-design-system-form的结构。
my-design-system-form/
__tests__/
Form.test.js
复制代码
在每一个package.json中,咱们都有测试的npm脚本。
"name": "@my-scope-name/my-design-system-form",
"scripts": {
"test": "jest"
}
复制代码
而后Lerna能够经过运行每一个测试脚原本执行。
lerna run test --stream
复制代码
*-stream 这个flag提供子进程的输出。
首先,你须要确保你已经登陆了。你能够经过如下操做来验证你是否已经登陆。
npm whoami // myusername
复制代码
若是你没有登陆,请运行如下内容并按照提示操做。
npm login
复制代码
登陆后,您能够经过运行Lerna发布。
lerna publish
复制代码
Lerna会提示你更新版本号。
Lerna支持使用Conventional Commits Standard在CI环境中自动进行语义版本管理。 这使开发人员可以像下面这样提交
git commit -m "fix: JIRA-1234 Fixed minor bug in foo"
复制代码
而后在CI环境中,包的版本能够根据上面的提交更新并发布到NPM。这能够经过配置你的CI环境来完成。
lerna publish --conventional-commits --yes
复制代码
若是你不想传递flag,能够在你的lerna.json文件中添加如下内容。
"command": {
"publish": {
"conventionalCommits": true,
"yes": true
}
}
复制代码
若是你想强制执行 Conventional Commits 标准,我建议在项目的ROOT中加入Commitlint。
yarn add @commitlint/cli @commitlint/config-conventional husky cross-env --dev
复制代码
而后在根package.json中建立一个发布脚本
"scripts": {
"release": "cross-env HUSKY_BYPASS=true lerna publish"
}
复制代码
这个发布脚本将在CI环境中运行。请注意,咱们在 lerna.json 文件中配置了传统的提交和 "yes "标志。因为这个CI环境将会把版本的变动提交,咱们不但愿触发提交消息的inting。咱们经过添加一个名为HUSKY_BYPASS的环境变量来实现,咱们将使用cross-env将其设置为true。 咱们还须要在root package.json中添加进一步的配置。
"husky": {
"hooks": {
"commit-msg": "[[ -n $HUSKY_BYPASS ]] || commitlint -E HUSKY_GIT_PARAMS"
}
},
"commitlint": {
"extends": ["@commitlint/config-conventional"]
}
复制代码
对于husky,咱们添加了一个commitlint/config-conventional的commit-msg钩子,它将检查咱们在上面添加的HUSKY_BYPASS环境变量,若是这个变量是假的,那么咱们经过@commitlint/config-conventional来精简提交消息。
若是出于任何缘由,你想彻底掌控版本控制,Lerna有能力将版本控制和发布分红两个命令。 你能够手动运行。
lerna version
复制代码
而后按照提示更新各个版本号。 而后你就能够有一个步骤,读取最新的标签(是手动更新的)发布到NPM。
lerna publish from-git --yes
复制代码
每当有新的贡献者对你的项目进行git克隆,或者你须要拉取你团队的最新变化时,你必须运行yarn命令。
yarn
复制代码
在大多数的Lerna教程中,提倡使用lerna bootstrap命令,然而当启用yarn工做空间时,这是没必要要的,也是多余的
lerna bootstrap when you're using Yarn workspaces is literally redundant? All lerna bootstrap --npm-client yarn --use-workspaces (CLI equivalent of your lerna.json config) does is call yarn install in the root. — Issue 1308
复制代码
在咱们的例子中,咱们正在构建一个多包设计系统。若是开发人员想在设计系统中建立一个新的组件,但在发布以前也要在本地客户端应用程序中进行测试,他们能够经过使用yarn的连接命令来实现。
假设咱们想在my-client-app中使用咱们本地的my-design-system-core。 咱们先cd到咱们要在另外一个项目中用到的软件包。
cd ~/path/to/my-design-system/my-design-system-core
复制代码
而后咱们建立一个symlink
yarn link
复制代码
你应该看到这样的输出
success Registered "@my-scope-name/my-design-system-core".
info You can now run `yarn link "@my-scope/my-design-system-core"` in the projects where you want to use this module and it will be used instead.
复制代码
如今咱们的包已经有了符号连接,咱们能够进入my-client-app中使用。
cd ~/path/to/my-client-app
yarn link @my-scope-name/my-design-system-core
复制代码
在 /packages/my-design-system-core 中的任何变化都会反映在my-client-app中。如今,开发人员能够很容易地在两个项目上进行本地开发,并看到它的反映。
当开发者完成后,再也不想使用本地的包时,咱们须要解除连接。 cd到入咱们要解除连接的包中
cd ~/path/to/my-design-system/my-design-system-core
复制代码
运行unlink删除本地symlink
yarn unlink
复制代码
你会看到这样的输出
success Unregistered "@my-scope-name/my-design-system-core".
info You can now run `yarn unlink "@my-scope-name/my-design-system-core"` in the projects where you no longer want to use this module.
复制代码
如今,咱们能够cd到my-client-app中解除连接。
cd ~/path/to/my-client-app
yarn unlink @my-scope-name/my-design-system-core
复制代码
Lerna与Yarn Workspaces是一个很好的组合。Lerna 在 Yarn Workspaces 的基础上增长了实用功能,用于处理多个包。纱线工做空间使得全部的依赖关系能够一块儿安装,使得缓存和安装速度更快。它让咱们能够经过一个命令轻松地在NPM上发布依赖关系,当依赖关系的版本发生变化时,自动更新兄弟依赖关系的package.json,通常来讲,安装、版本管理和发布都是一种无痛的体验。