Monorepo 项目管理Lerna

一、项目中遇到的问题

      最近在开发小程序的UI库,组件拆分力度比较细,都是一个个的单独的package包, 模块的复用性和灵活性达到最大化,实操的过程中,会遇到以下问题:

     1、维护成本较高,任何的基层 repo 版本变更,将会引发一系列上层封装版本变动

     2、版本发布npm包,代码不够规范,很多都不是发布master

     3、一个包一个repo,每次需要找到对应的仓库

     4、changelog 梳理异常折腾,有些基本上都没有changelog

 

基于上面的问题,有没有一种能解决我们问题的技术呢?

 

二、Monorepo 项目管理

    Monorepo 的全称是 monolithic repository,即单体式仓库,与之对应的是 Multirepo(multiple repository),这里的“单”和“多”是指每个仓库中所管理的模块数量。

    Multirepo 是比较传统的做法,即每一个 package 都单独用一个仓库来进行管理。例如:Rollup, ...,上面遇到问题的也是采用的这种方式。

    Monorep 是把所有相关的 package 都放在一个仓库里进行管理,每个 package 独立发布。例如:React, Angular, Babel, Jest, Umijs, Vue ...

    Multirepo和Monorep优劣势对比如下:

    

 

三、Monorepo 管理工具Lerna

Lerna 是一个管理多个 npm 模块的工具,是 Babel 自己用来维护自己的 Monorepo 并开源出的一个项目。优化维护多包的工作流,解决多个包互相依赖,且发布需要手动维护多个包的问题。

Lerna 现在已经被很多著名的项目组织使用,如:Babel, React, Vue, Angular, Ember, Meteor, Jest 。

1、lerna模式

在初始化一个项目之前我们必须要清楚,lerna 对管理 monoRepo 有两种模式

  • Fixed/Locked mode (default)
  • Independent mode

Fixed/Locked 模式: 官方默认推荐模式,当前 babel 的项目管理模式,在该模式下所有的 packages 都会遵循一个版本号,该版本号维护在 lerna.json 的 version 字段中,当需要版本发布时 lerna publish 时,如果一个模块和上一次 release 相比有过变更的话,会自动发布一个新版本。

这种模式的问题在于:当有一个 major 变更的时候,所有 packages 都会都会有一个新的 major 版本。

维护团队认为:版本是一种非常 cheap 的东西,所以不必纠结。

Independent 模式: 在该模式下所有 packages 新版本的生成将会由开发者决定,lerna.json 的 version 字段也会随之失效。这种模式的弊端非常明显,开发者必须要非常清晰该发什么版本,事实上在多人协作项目上很难做到这一点。

 2、如何使用lerna

    a、全局安装lerna

npm i -g lerna

 

    b、初始化项目

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

   初始目录如下,接着进行开发

 

     c、建立 packages 的依赖关系

lerna bootstrap

     

    这个命令会安装好所有 packages 的依赖,以及建立好 packages 相互依赖的软连接

    正式流程为:

  1. 安装所有 package 的外部依赖.
  2. 对存在相互依赖的 package 创建软连接.
  3. 在所有已经 bootstrapped 的 package 中执行 npm run prepublish.
  4. 在所有已经 bootstrapped 的 package 中执行 npm run prepare.

       当然我们使用 --hoist 来把每个 package 下的依赖包都提升到工程根目录,来降低安装以及管理的成本。

lerna bootstrap --hoist

 

   

   如果以前安装了依赖,发生改动,可以先清理一下安装的依赖即可:

lerna clean

 

    d、发布版本

lerna publish

   正式流程为:

  1. 执行 lerna updated 来确定哪些包需要被发布.
  2. 如有必要会升级 lerna.json 的 version 字段。
  3. 对所有需要 update 的 package 进行版本的更新,并写入他们的 package.json.
  4. 对所有需要 update 的 package 进行依赖申明 specified with a caret (^).
  5. 创建一个 git commit 和 tag
  6. 把包发布至 npm

 

四、生成changelog

     由于本项目后期需要对外,使用基于PR来生成changelog的lerna-changelog,项目建议使用cz-lerna-changelog 。

     1、安装lerna-changelog

npm install lerna-changelog --save-dev

     

     2、修改 lerna.josn 需要新增相关 lerna-changelog 所需要的配置,此处参考babel配置

"changelog": {
    "repo": "binglingwy/lerna-test-new",
    "cacheDir": ".changelog",
    "labels": {
      "PR: Breaking Change :boom:": ":boom: Breaking Change",
      "PR: New Feature :rocket:": ":rocket: New Feature",
      "PR: Bug Fix :bug:": ":bug: Bug Fix",
      "PR: Docs :memo:": ":memo: Documentation",
      "PR: Internal :house:": ":house: Internal",
      "PR: Performance :running_woman:": ":running_woman: Performance"
    }
  },

     注意:labels 的 key 必须在 github 的仓库内定义好

     3、设置令牌

export GITHUB_AUTH="..."

GITHUB_AUTH 的 token 字段可以在github 申请 token 获得。

   4、创建个PR

        a、拉一个新的分支

        b、修改代码并提交,提交记录记得关联issues,例如:

git commit -a -m "module-base: bug fixed, Close #1"

        c、推送代码,并在github上创建PR

       注意:在创建 pr 时一定要选择对应的 label ,label需提前在github建好,跟lerna.josn一致

        d、合并pr到主干,切换到本地master,生成changelog

node_modules/.bin/lerna-changelog

      e、一旦 publish 后我们便可以创建 release note,效果如下

     

 当然也可以在生成文件CHANGELOG.md,在lerna.json中添加conventionalCommits配置:

"command": {
    "publish": {
      "allowBranch": "master",
      "conventionalCommits": true
    }
  }

配置后,当我们执行lerna publish后会在项目根目录以及每个packages包下,生成CHANGELOG.md

注意: 只有符合约定commit提交才能正确生成CHANGELOG.md文件。

 

参考文章

Lerna 官网:https://github.com/lerna/lerna/blob/master/README.md

lerna-changelog:https://github.com/lerna/lerna-changelog

手摸手教你玩转 Lerna: http://www.uedlinker.com/2018/08/17/lerna-trainning/

posted @ 2019-11-12 11:26  三宝123  阅读(1143)  评论(0编辑  收藏  举报