基于 Rush 实现 Monorepo 的入门体验
本文参考官方文档学习后总结了关于 Monorepo + Rush + PNPM 的入门实践,以更容易理解的方式组织了文章结构,如果你也需要构建一个大型多项目仓库,不妨可以看看本文
- 本文不对 Monorepo 做介绍
为什么需要 Rush?Rush 解决了什么问题?
rush是为大型团队准备的,它可以给你提供一个仓库下维护多个项目的构建和发布方案。
包管理存在的问题:当我们使用 Monorepo 的方式来组织项目时,为各项目安装依赖的过程中可能会出现各种问题(如幻影依赖(phantom dependencies)、NPM 分身(doppelgangers))
- Rush 使用符号链接来为每个项目重新构建一个准确的 “node_modules” 文件
- Rush 一次性安装全部原始依赖在 root 下的 common/temp 目录下,从该目录下提供 Symlink 给到个项目去引用。
Rush 还有什么新特性?
提供项目间自动 link
多线程构建多项目,加快构建速度
自动检测有改动的项目,按配置产出版本号和 changelog
前置知识
shrinkwrap 文件
shrinkwrap 文件是 包管理器的一项功能。可以按照当前项目 node_modules 目录内的安装包情况生成稳定的版本号描述。
- 可能是 shrinkwrap.yaml, npm-shrinkwrap.json, package-lock.json, 或 yarn.lock
- 由于我们并不知道你使用了哪种包管理工具,因此使用 “shrinkwrap” 来泛指这些文件。
通常,包管理工具会在每个项目文件夹内创建 shrinkwrap 文件,但是在 Rush 中,整个项目共用存储在
common/config/rush
“ 目录下的一个 shrinkwrap 文件,它会被存储在 Git 内。
- 将所有依赖信息整合到单独一个 shrinkwrap 内有一些优势,例如减少冲突、方便查看 diff, 还能提高安装速度。
快速开始
环境准备
安装长期支持的 NodeJS,当然也可以用 nvm 去管理 NodeJS 的版本
以 win 10 演示
Rush 应该结合哪个包管理工具呢?
目前比较主流的包管理工具有:NPM、YARN、PNPM
用哪个包管理工具都是视需求而定的,每个包管理工具都有自己的利弊,但如果是 Monorepo + Rush,则推荐用 PNPM
- PNPM 能解决 NPM 分身的问题,因为复杂的 Monorepo 中这个问题还是比较容易出现的
安装 Rush
全局安装 Rush(以管理员身份运行命令行窗口)
1 | 安装 |
目录规范
- apps:MWA 应用,如 Web、H5、Electron 应用等
- examples:模板、示例、演示项目等
- features:可复用的业务模块
- 如请求状态码的处理
- 需要客户端和服务端共用部分逻辑
- services 后端服务
开启新项目
目的:使用 rush 实现 monorepo 项目管理
初始化
1.新建 gitlab 仓库 monorepo-rush
- 克隆到本地
- 进入仓库后进行初始化
1 | rush init |
主要生成以下目录,更多请查看
1 | monorepo-rush |
如果你的分支中已经存在这些文件,
rush init
将会发出警告并且不会覆盖已有的文件
自定义配置
配置文件中已经有大量的示例了
rush.json 必须要了解的几个配置
1 | { |
新建 React 项目
根据规范,前端项目需要在根目录的 apps
目录下创建
请自行安装脚手架
1 | mkdir apps |
删除一些可能有影响的文件
- 删除本地的 shrinkwrap 文件,因为它会被 Rush 的 shrinkwrap 文件代替。
- 考虑删除 .npmrc 文件,因为 Rush 使用了 common/config/rush/.npmrc.
- 考虑删除项目的 Git 配置文件,除非该项目有单独的配置。
1 | cd my-apps |
告知 Rush 需要接管 my-app 这个项目
- 编辑 rush.json
1 | "projects": [ |
为什么 Rush 不能自动检测到这个项目?
Rush 并不会使用通配符来检测项目。该设计有以下考虑:
- 深度优先搜索开销太大,尤其是需要重复收集列表时;
- 在带有缓存的 CI 机器上,搜索可能会遗漏掉之前构建中的文件;
- 集中式的管理所有项目以及其重要的元数据是很有用的,例如,可以让审批等策略更简单。
执行 rush update
安装依赖
1 | rush update |
如果这是仓库内的第一个项目,你将会发现 rush update
创建了一些新文件:
- common/config/rush/pnpm-lock.yaml: 公共的 shrinkwrap 文件 (此处假定使用了 PNPM)
- common/scripts/install-run-rush.js: 用于在 CI 任务中以一种可靠的方式来启动 Rush
- common/scripts/install-run.js: 用于在 CI 任务中以一种可靠的方式来启动任意工具
验证新项目是否构建成功
1 | 在根目录下 |
Rush 通常会使用系统的 PATH 环境变量来查找脚本,然而,如果你制定了诸如 “gulp” 或者 “make” 等单个单词的指令,Rush 会首先在
common\temp\node_modules\.bin
目录下查找该指令。如果进程返回非零退出码,Rush 将判定为失败,并阻塞随后的构建。
如果指令对
stderr
存在任意输入,则 Rush 将以错误、警告报告等形式来解释该输入。这将会中断构建流程(设计如此,如果你允许开发者以这种 “狼来了” 的形式合并 PR,很快你就会发现,报警提示很快就会堆积到没人再去看它们)。诸如 Jest 等的工具库认为向stderr
写入信息是常见操作,对此需要你重定向它们的输出.即使某个项目不需要被
rush build
处理,你依然需要保留build
字段,将其设定为空字符串(""
) 后 Rush 会忽略它们。
常用命令
rush update
- 当 package.json 文件发生变化时,请务必运行
rush update
rush update
内做了些什么:
- Rush 检查或应用各种可能会改变 common/config 内文件的策略。
- Rush 会将所有项目内的 package.json 文件与仓库的公共 shrinkwrap 文件进行比较来检查是否有效。
- 若无效,则包管理工具会更新 shrinkwrap 文件。
- 无论如何,包管理工具都会将所有依赖安装到 common/temp/node_modules 目录下。
- 最后,Rush 会给每个项目下构建一个 node_modules 文件夹,该文件夹下内容通过符合链接到 common/temp/node_modules. (该操作等同于
rush link
)
CI 流水线中使用
rush install
来替代rush update
, 二者的不同点是rush install
不会更新任何文件,相反,如果存在过失的数据,则会在 PR 上报错,并提示你执行rush update
或者提示你 commit 其结果。(一些开发者为了防止 shrinkwrap 文件中不符合预期的更新,他们选择使用rush install
当作常用指令,而不是rush build
)
rush rebuild
- 给仓库内的所有项目执行一个完整的、清除式的构建。
- 如果你的工具链支持增量构建,那么你可以执行
rush build
来构建那些变动过的项目。
rushx
- 仅仅想构建一个项目,在对应的项目下运行
rushx
指令,该指令相当于npm run
1 | rushx build # npm run build |
rush change
如果你从事库会被 NPM 发布,那么你的仓库可能需要你在 PR 中添加相应的变更日志。如果没有添加,你的 PR 构建会在 rush change --verify
步骤失败。
为了书写变更日志,首先需要把变动以 commit 的形式提交到 Git 中,之后在仓库下执行 rush change
, 该指令会检查 Git 历史,并根据变动情况提示你为每个变化的项目书写更新日志。每一条日志会被存储在 common/changes 下的独立文件中。你应该把这些文件添加到 Git 中,以便于后续的提交。
随后,Rush 的自动发布工作流会检查这些文件,以确定哪些包需要发布。它会删除这些文件,并将你的更新信息复制到包的 CHANGELOG.md 文件中。
⏵ 查看 更新日志编写 来获取更多写变更记录的提示。
rush scan
rush scan 指令可以快速地检查出幻影依赖的问题
日常使用组合
1 | 从 Git 获取最新的代码 |
注意事项
不要用包管理工具安装或链接依赖
Rush 会在某个中心文件夹安装所有的依赖,之后使用符号链接给每个项目创建 “node_modules” 文件夹。
- 不要使用包管理工具来安装或链接依赖。
- 避免使用
npm install
、pnpm install
、yarn install
等操作,这些命令会干扰 rush 的符号连接。如果要使用,必须先执行rush unlink
清除符号链接
- 避免使用
- 如果想执行
git clean -dfx
清理文件夹,必须先执行rush unlink
清除符号链接,因为它对符号链接的处理并不好
如何重新生成符合链接?
- rush update
强制重装所有包
Rush 的包管理工具命令是“增量”式的,Rush 有很多措施保证正确性。但是当你在本地调试时,有时会导致你的 NPM “node_modules” 文件夹变得不正确,最终导致奇怪的错误。
- 执行
rush update --purge
强制重新安装所有包
最后
这里只是rush 的入门学习指引,更多内容可以查阅官网进行学习