lerna入门指南
一.定位
Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.
多模块管理工具,用来帮助维护monorepo
P.S.Lerna是Babel自己日用并开源的工具,见Why is Babel a monorepo?
二.monorepo
monorepo(monolithic repository),与multirepo相对,分别是单代码仓库与多代码仓库(one-repository-per-module)
multirepo即传统做法,按模块分为多个代码库,实践中发现一些问题:
issue管理混乱,经常有在core repo提module问题的,需要Close this and track that
changelog难以整合,需要人工梳理所有变动的仓库,并做整合
core repo版本更新麻烦,需要同步所有module更新其依赖的core repo版本
monorepo把所有相关module都放到一个repo里,每个module独立发布,但使用与该repo统一的版本号(例如Babel和React),issue和PR都集中到该repo,changelog可以简单地从一份commit列表梳理出来(甚至如果按照commit规范关联issue tag的话,能够自动生成规范的changelog)
monorepo也存在一些问题,但不如上面提到的痛点强烈:
repo体积较大,可能带来版本控制的问题(Git不适合管理体积太大的repo)
统一构建工具,对构建工具提出了更高要求,要能构建各种相关module
从源码管理的角度来看,multirepo与monorepo是两种不同的理念,前者允许多元化发展,各个module可以有自己的玩法(构建,依赖管理,单元测试等),后者希望集中管理,减少玩法差异带来的沟通成本
monorepo标志性的特征是目录结构,例如React:
react-16.2.0/ packages/ react/ react-art/ react-.../
每个module都有自己的依赖项(package.json),能够作为独立的npm package发布,只是源码放在一起维护
典型案例:
rollup:multirepo
babel:monorepo
P.S.之前使用rollup遇到问题都先去主repo查相关issue,再根据线索找到对应的plugin repo,再查相关issue。一直感觉异常麻烦,又说不出来哪里不对,原来是源码组织方式带来的困扰
三.lerna试玩
// 安装 npm install lerna -g git init hoho-lerna && cd hoho-lerna // 初始化目录结构 lerna init
得到如下结构:
hoho-lerna/ packages/ lerna.json package.json
创建module:
mkdir packages/hoho-lerna-core && cd packages/hoho-lerna-core npm init
这样最终会得到一堆package:
packages/ hoho-lerna-core/ package.json hoho-lerna-module-a/ package.json hoho-lerna-module-b/ package.json module.../
我们实际做的事情是按模块拆分成package,并(通过module级的package.json)声明了各package之间的依赖关系
依赖处理
如果moduleA依赖core,通过lerna bootstrap命令处理依赖过后,会在moduleA的node_modules下创建软链接指向core目录,有一只活生生的例子
注意:npm不会自动安装peerDependencies,lerna也不提供这个服务
lerna bootstrap按照之前声明的依赖关系,通过建立软链接来把各package实际关联起来
发布package
既然都放在packages里了,容易统一管理,所以支持一键发布所有package到npm
P.S.先要有npm账号(自行注册),并npm adduser添加到本地配置里
准备好之后,迫不及待的开始一箭n星:
lerna publish
不出意外的话,会得到类似输出:
lerna info version 2.7.0 lerna info current version 0.0.0 lerna info Checking for updated packages... lerna info Comparing with initial commit. lerna info Checking for prereleased packages... ? Select a new version (currently 0.0.0) Major (1.0.0) Changes: - hoho-lerna-core: 1.0.0 => 1.0.0 - hoho-lerna-module-a: 1.0.0 => 1.0.0 - hoho-lerna-module-b: 1.0.0 => 1.0.0 ? Are you sure you want to publish the above changes? Yes lerna info publish Publishing packages to npm... lerna info published hoho-lerna-module-b lerna info published hoho-lerna-core lerna info published hoho-lerna-module-a lerna info git Pushing tags... Successfully published: - hoho-lerna-core@1.0.0 - hoho-lerna-module-a@1.0.0 - hoho-lerna-module-b@1.0.0 lerna success publish finished
然后,npm registry里就多了3个垃圾package……
publish的大致过程是:
本地打个tag(例如git tag v1.0.0)
自动更新依赖项版本号 示例
然后把各个package发布到npm
最后把tag和相应的commit给push上去
注意:如果发布到npm这一步失败了的话(比如没配置npm账号),下一次直接lerna publish无法直接发布,貌似因为本地tag已经是v1.0.0认为上次发布成功了。把这个tag手动滚掉也不行,.git里可能记了一些发布状态,滚掉之后出现commit hash匹配错误,这里不太友好
P.S.更多命令请查看Lerna
自动生成changelog
先安装changelog工具:
npm install lerna-changelog -g
然后在lerna.json添加对应配置项:
"changelog": { "repo": "ayqy/hoho-lerna", "labels": { "enhancement": ":rocket: Enhancement", "bug": ":bug: Bug Fix", "doc": "Refine Doc", "feat": "New Feature" }, "cacheDir": ".changelog" }
特别注意:repo是必填的,说是能自动推断,实际上不太靠谱,见The ‘repo’ field automatically inferred failed, but no error occurred
P.S.labels里,key是要在Github配置的标签,用来给Issue/PR分类,value里的:bug:只是调皮的emoji,会作为changelog里该类change的标题
到这里还不算完,还需要Github repo权限(为了能查Issue、PR),把token以环境变量的形式暴露出来(常用的话,可以添到~/.bash_profile里):
export GITHUB_AUTH="..."
配置完毕。要达到“自动”,前提是日常开发维护遵守约定的规范,否则最后工具肯定猜不出来changelog。规范是指:
(建议)commit message关联上对应的issue
(必须)创建PR时要选择我们预定义的label
因为工具只整理github带有指定label的PR,并把commit message作为changelog项,建议commit message里关联上issue,生成的changelog就能关联到对应issue:
Uses github PR/Issue names categorized by labels with configurable headings.
例如:
git cm -m "feat: changelog, Close #1"
然后提交PR并给贴上label:feat,merge之后,本地pull过来试试lerna-changelog:
## Unreleased (2018-01-13) #### New Feature * [#2](https://github.com/ayqy/hoho-lerna/pull/2) feat: changelog, Closes [#1](https://github.com/ayqy/hoho-lerna/issues/1). ([@ayqy](https://github.com/ayqy)) #### Committers: 1 - 黯羽轻扬 ([ayqy](https://github.com/ayqy)) 相当漂亮:https://github.com/ayqy/hoho-lerna/releases/tag/v1.1.0
P.S.应该在.gitignore忽略掉本地生成的changelog临时文件,仅在发布新版本时本地lerna-changelog,并把生成的changelog贴到release note。不自动发布release note可能是API限制或出于慎重考虑,毕竟release note还是比较重要的
另外,以这种方式自动整理出changelog,实际上靠的是开发中约束(PR的label规范,commit message作为changelog项的规范),与lerna没有太大关系,只要是monorepo(Issue/PR)都放在一起,就可以按照这个思路获取Issue/PR信息,整理出changelog
相当于把最后梳理changelog的巨大工作量分布到日常开发维护了,change都要走PR,而且要有issue记录,不习惯的话还是很麻烦的(有要求commit message自带label而不走PR的呼声,以后应该会支持)
四.适用场景
哪些场景可以采用monorepo(并用lerna管理?)?
不过分庞大的项目,整合到一起有100G源码的话,还是再考虑一下吧
多模块/插件化项目,把官方维护的插件都作为package非常合适
另外,还需要:
基础建设
团队信任
基础建设是指强大的构建工具,能满足所有模块的build需求(纯前端项目的话,build压力不大)
monorepo环境下,可以并且鼓励改别人的代码,一方面需要持续集成机制(例如React – CircleCI)确认修改带来的影响,另一方面还需要不同团队之间互相信任,否则会经常出现一个团队的变更影响了另一个团队的情况,需要回滚掉别人的修改,反而影响效率
P.S.Lerna出来很久了(和Babel差不多年纪),很多项目都在用了
参考资料
Lerna:很简练的官方文档
monorepo 新浪潮 | introduce lerna:前辈的helloworld还不错
REPO 风格之争:MONO VS MULTI
Mono Repository Tool Comparison:monorepo工具对比
New wave modularity with Lerna, monorepos, and npm organizations
- Maven入门指南⑦:Maven的生命周期和插件
- linux常用命令之bash 入门指南
- _信息安全入门指南
- 《WalkThrough WebPart 入门指南二》完成
- Kafka Streams入门指南
- Cordova 应用程序创建入门指南
- 掌握VS2010调试 -- 入门指南
- Firebug入门指南
- ncurses 入门指南
- Asp.Net MVC4入门指南(7):给电影表和模型添加新字段
- CMake入门指南
- Asp.Net MVC4.0 官方教程 入门指南之三--添加一个视图
- Solaris供职料理工具 SMF疾速入门指南(2)
- 5+ App开发入门指南
- 自然语言处理(NLP)入门指南资料
- libusb开发者入门指南
- Velocity入门指南——第二章 注释
- 【Docker】Docker使用入门指南
- 【OpenCV入门指南】第一篇 安装OpenCV
- GitHub入门使用指南