lerna + yarn workspace
常见的npm包代码的管理分为两种方案
multirepo
:把项目按模块拆分为多个库monorepo
:把所有项目放在单个仓库中
multirepo
- 优点:有自己的仓库,可以使用擅长的技术,工具,工作流程等,效率比较高
- 缺点:代码质量得不到保证,如果项目之间存在依赖关系,修复某个项目得到bug需要同步到其他的项目,依赖相互引用的话 引用方式需要考虑
monorepo
- 优点:能够统一管理代码,代码风格以及质量能够得到保证。
- 缺点:都用同一种技术方案,效率可能会降低。
真正的需要考虑的是 规范大于一切,无规矩不成方圆,如果风格各异并不便于团队开发,互相做版本迭代的时候 同样会降低开发效率。并且如果A依赖于B,B发现了BUG并且发版本hotfix,那么A同样也需要进行发版。维护会非常困难。
而monnorepo模式可以依赖工具,根据module之间的关系,同时发布A,B的依赖版本。
- lerna create [package] 创建一个package到项目的packages下
- lerna add [module] 为每个package都安装依赖
lerna add react
- 为指定的package安装依赖
lerna add react-dom packages/package1
//or
lerna add react-dom --scope=package1
- 添加依赖到根目录 node_module中
npm install typescript -d
- package之间的互相依赖(会在package/package.json下添加依赖):
lerna add package2 --scope package1
// or
lerna add package2 package/package1
- lerna bootstrap用于将packages连接在一起(前提是相互依赖的库),并安装到package下的依赖搭配package/node_modules
- lerna clean 删除各个包下的node_modules 不会删除根目录的node_modules
- lerna ls列出当下lerna仓库下的所有公共包
- lerna run test运行每个包下面的script 的test命令
- lerna run test —scppe package1 单独运行package1的test命令
- lerna changed检查自上次发布以来哪些软件包被修改过
- lerna link 连接相互引用的库,当package/package.json内明确了packages下的包的时候,才会将相关的包链接到package/node_modules中
- lerna info 查看lerna及运行环境信息
版本发布
packages下的包版本发布需要使用lerna publish
,这个命令组合了两个命令,lerna-version和npm publish。
其中lerna-version针对lerna的管理模式(固定模式和独立模式),在表现上是不同的。
但主要工作还是在进行npm publish之前,去管理哪些包要进行发布,以及发布过程中生成的Git commit,git tag的提交。
- 固定模式下的lerna verison:
- 找出从上个版本发布以来有所变更的package
- 根据当前lerna.json中的版本生成新的版本号
- 更新涉及到变更package下的package.json版本号
- 更新lerna.json文件中的版本号
- 将version更新,生成CHANGELOG.md文件带来的变动提交为一次commit
- 基于这次commit为所有涉及到更新的package打上各自的tag
- 推送commit和tags到远程仓库
- 独立模式下的lerna version
- 找出上一个版本发布以来有所变更的package
- 提示开发者为需要更新的package选择要发布的版本号
- 更新到package下的package.json version版本号
- 如果packages下其他包有依赖这个包,那么这些包下的package.json中此包版本也会更新
- 将version的更新变动提交为一次commit
- 基于这次commit为所有涉及到更新的package打上各自的tag
- 推送commit和tags到远程仓库
初次使用发布时可能会遇到以下的问题和注意事项
- 避免开发者自己去打tag.lerna发布时会自动生成tag,并且查找更新是基于tag来识别的,避免开发者手动打上tag后,影响lerna查找变更,可能会造成一些变更包没有按照预期发布
- 避免多条分支同时进行。在多条分支同时进行时,可能会生成相同的版本号,从而发生版本冲突。解决方法:分支开发者之前应该提前约定版本信息
- lerna publish发布途中失败了,如果重新发布。有时候发布可能会失败,再次运行lerna publish时,因为tag已经打上了,无法再次查找更新,进行包的发布。
可以采用以下两种发布方式:
- 运行
lerna publish from-git
会将当前的标签中涉及到的NPM包再发布一遍(不会再次更新package.json 只是运行npm publish) - 运行
lerna publish from-package
会将当前所有本地包中的package.json和远端npm对比,如果npm上不存在此包的最新版本,都会执行一次npm publish
最佳实践
lerna + yarn workspace 结合的Monorepo方案,两者工作职责划分不同:
- yarn 处理依赖安装工作(只想做好包管理工具)
- lerna 处理发布流程
yarn管理命令大致分为两类
- 处理工程下指定的包模块时使用:
yarn workspace
- 处理工程根目录全局或所有包模块时使用:
yarn workspaces
- yarn install代替npm install. + lerna bootstrap安装工程依赖
它与lerna bootstrap不同的是:
- yarn install 会将package下的依赖统一安装到根目录下。这有利于提升依赖的安装效率和不同package间的版本复用(有些包需要私有依赖的,而私有以来回被多个包安装多次,而提升依赖可以解决这个问题)
- yarn install会自动帮助解决安装 包括根目录下的安装 和package link的问题
- yarn add [module]
- 为每个package都按组昂制定的依赖
yarn workspaces add react
- 为制定的package安装特定依赖:
yarn workspace package1 add react react-dom --save
- 添加依赖到根目录node_modules中
yar nadd @babel/core -D -W(w 表示依赖天假到workspace根目录下)
- package之间的相互依赖(会在package/package.json下添加依赖)
yarn workspace package1 add package2
- 在工程目录下引入packages/package包
yarn add package@1.x.x -W
- yarn remove [module] 和add命令格式一样。
- 运行工程根目录下的script
yarn test
- 运行指定包模块下的script
yarn workspace package1 run test
- 运行所有package下的script命令
yarn workspaces run test