You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In version control systems, a monorepo ("mono" meaning 'single' and "repo" being short for 'repository') is a software development strategy where code for many projects is stored in the same repository.
由于最近负责抽象公司项目模块化成 SDK,故预研了 Monorepo 、Lerna、yarn workspaces 管理多模块的方案,记一笔调研结论。
方案调研
采用维基百科的解释:
也就是说 Monorepo 是版本管理系统中的一种“开发策略”,宏观上说就是单 repository 管理多 projects(packages) 。
采用 Monorepo 管理多模块的优势以及与单 package 单 repo 的对比:
若单模块 A 就是一个 repo,要 npm link 给别的 repo 调试,且 A 源码修改了,得重新 npm link 一次。 Monorepo 的话,则是动态引用的各模块。
各模块统一发布,有一个依赖模块改变了,会自动改变依赖与被依赖模块的版本号,且可以选择统一|分别控制版本号的处理。(Fixed | Independent mode)
单模块单 repo 的话,改变了依赖模块 A,手动修改版本号发布后,得手动去找被依赖模块且改版本号然后发布。repo 越多越麻烦。
不会装各 packages 间的重复依赖,所有依赖提升到根目录。(导致的缺点就是只调试一个包也要装全部依赖)
因为就一个 repo,commit 可以借工具规范生成 changelog 。
缺点就是一个 repo 的体积过大。但相对以上前三点来说,可以接受。
根据调研,一个理想的 monorepo 结构:
所有全局配置文件只有一个,这样不会导致 IDE 遇到子文件夹中的配置文件,导致全局配置失效或异常。
node_modules 也只有一个,既保证了项目依赖的一致性,又避免了依赖被重复安装,节省空间的同时还提高了安装速度。
兄弟模块之间通过模块 package.json 定义的 name 相互引用,保证模块之间的独立性,但又不需要真正发布或安装这个模块,通过 tsconfig.json 的 paths 与 webpack 的 alias 共同实现虚拟模块路径的效果。
再结合 Lerna 根据联动发布功能,使每个子模块都可以独立发布。
再根据对别的团队 Monorepo 方案调研结果,决定采用 yarn workspaces + lerna 方案管理,也是 yarn 官方推荐的方案,核心是:使用 yarn workspaces 来管理依赖,使用 lerna 来管理 npm 包的版本发布。
Lerna + yarn workspaces
以下是自己建 demo repo 跟着文档尝试后,小记的常用指令及含义。 也建议亲自折腾下体会更深。
Combine yarn workspaces and Lerna
因 lerna 本身就是基于 yarn 、npm、git 开发,所以在利用 lerna 构建好项目后开启 yarn workspace 功能仅作如上配置即可。
Lerna
lerna init
创建 lerna 仓库,默认 Fixed 模式。
lerna init --independent
可以创建 Independent 模式。lerna create xxx
创建新模块
lerna add <package>[@version] [--dev] [--exact] [--peer]
假如有两个 package-1, package-2,。
lerna add babel
, 该命令会在package-1和package-2下安装babellerna add react --scope=package-1
,该命令会在package-1下安装reactlerna add package-2 --scope=package-1
,该命令会在package-1下安装package-2 (软链)lerna bootstrap | yarn install
安装所有依赖项并链接所有的交叉依赖
lerna exec
在 packages 中对应包下的执行任意命令。
如要执行 package-A 下的
yarn start
:lerna exec --scope package-A -- yarn start
如果不带 --scope package,则默认在根目录执行,如
lerna exec -- rm -rf ./node_modules
lerna run --scope my-component test
执行 my-component 下的 npm scripts
test
lerna ls
查看 packages
lerna list --json
带路径一起查lerna changed/updated/diff
查出待 publish 的 packages
diff
的话会可视化修改不主动
git commit | tag
的话,lerna 不会检测到,lerna 底层就是基于 git npm 开发的lerna clean
删除 packages 下的 node_modules
(lerna clean 不会删除项目最外层的根 node_modules)
lerna publish
发布 packages 到 npm 仓库,发包前需要登录 npm 账号,否则会上传 git 成功,上传 npm 失败。
(package.json 中的 ”private“: true 不会发布)
该命令也有许多的参数,例如
--skip-git
将不会创建 git commit 或 tag,--skip-npm
将不会把包 publish 到 npm 上。yarn workspaces
yarn install
跟
lerna bootstrap
效果一致,会自动帮忙解决安装和 link 问题yarn workspaces info
各 package 依赖树关系
安装 | 删除依赖
i. 给某个 package 安装 | 删除依赖:
yarn workspace packageB add packageA@xx.xx.xx
将 packageA 作为 packageB 的依赖进行安装,如果想要不同 package 间的 link,必须明确指定版本号。yarn workspace packageB add -D react
删除:
yarn workspace packageB remove packageA
ii. 给根目录 安装 | 删除依赖(适用所有 packages):
yarn add -W -D commitizen
root package 安装 commitizenyarn remove -W commitizen
root package 移除 commitizen执行
scripts
运行 packageA 的 dev 命令:
yarn workspace packageA dev
每个工作区运行命令:
yarn workspaces run xxx
最佳实践
除了以上 ,最佳实践决定参考 vivo 团队实现 与 淘系团队实现,之后开发过程中,再根据项目自身情况进行调整。
The text was updated successfully, but these errors were encountered: