Monorepo 可以协助微前端项目,因为它可以提供一个集中式的代码库和版本控制系统,使得多个微前端应用可以共享代码和资源,并且可以更容易地进行协作和集成。通过 Monorepo可以更容易地管理共享的组件、库和工具,以及更方便地进行测试、构建和部署。
当下前端组件库 / 工具库的最佳实践方案基本都是 pnpm + monorepo 的开发模式,如 Vue、React、Vite、Element UI、Vant UI 等。
1. Monorepo 模式
Monorepo是一种项目开发与管理的策略模式,它代表"单一代码仓库"(Monolithic Repository)。在 Monorepo模式中,所有相关的项目和组件都被存储在一个统一的代码仓库中,而不是分散在多个独立的代码仓库中,这些项目之间还可能会有依赖关系。
引申:
| 开发模式 | 解释 |
|---|---|
| Monolithic(单体应用)开发模式 | 整个应用程序由一个单一的代码库、构建和部署流程组成。这种模式简单易懂,适合小型项目。 |
| Multirepo(多仓多模块)开发模式 | 每个仓库独立维护自己的代码和构建流程。这种模式更适合大型和复杂的项目,因为它提供了更好的隔离性和独立性,同时可以更灵活地管理多个团队的工作。 |
| Monorepo (单仓多模块)开发模式 | Monorepo 是一种试图回归单体管理优势的方法,但保留了多仓库开发的某些优点。它允许在一个代码库中管理多个项目、组件或服务,提供更好的代码共享和重用性。 |
2. 解决哪些痛点
- 代码共享和重用:Monorepo 允许不同的项目、模块或服务之间共享代码和依赖关系,这样可以避免代码的重复编写和维护。开发团队可以更轻松地在不同的项目之间共享通用组件、库和工具。
- 依赖管理:Monorepo 提供了更简单和一致的依赖管理。在传统的多仓库环境中,不同的项目可能需要维护自己的依赖关系,这可能会导致版本冲突和复杂的依赖链。使用 Monorepo,所有项目都可以使用相同的依赖版本,使依赖管理更加统一和可控。
- 构建和测试:Monorepo 可以提供更高效的构建和测试流程。由于所有的代码都存储在同一个仓库中,构建和测试工具可以更容易地跨项目进行优化和并行化。这可以减少构建和测试时间,提高开发团队的生产力。
- 跨项目协作:Monorepo 促进了团队内部的协作和交流。开发人员可以更方便地查看和理解其他项目的代码,提供反馈和建议。这也有助于知识共享和技术传承,使团队成员能够更好地理解整个代码库的架构和设计。
- 一致的版本控制:在 Monorepo 中,所有的代码都受到相同的版本控制策略的管理。这意味着可以更容易地跟踪和管理代码的变更历史、回滚错误的更改,并确保不同项目之间的代码保持一致性。
在选择 monorepo 和 multirepo 方案时需要考虑项目的规模和复杂度,以及团队的开发流程和协作方式等因素。如果项目规模比较小或者团队比较紧密,可以考虑选择 monorepo 方案;如果项目规模较大或者团队比较分散,可以考虑选择 multirepo 方案。
3. Monorepo 技术选型
| 方案 | 描述 |
|---|---|
| Lerna + Yarn Workspaces | 1. Lerna 文档是可以的(但不够详细) 2. Yarn Workspaces(v1)已经不再维护(上次更新是在 2018) 3. Lerna 学习笔记 |
| pnpm + pnpm Workspaces | pnpm 旨在解决两个大问题: 1. 磁盘空间 2. 幽灵依赖 |
推荐使用更轻量的 pnpm 来实现 Monorepo 项目,如果有对版本控制有需求,可以配合 changesets 实现。
4. Workspace 模式
包管理工具通过 workspace 功能来支持 Monorepo 模式。Workspace 是指在一个代码库中管理多个相关项目或模块的能力。
前端目前最主流的三款包管理工具 npm、yarn、pnpm 都已经原生支持 workspace 模式,我们都可以实现其与 monorepo 的配合,但最终依然选择 pmpm 作为包管理工具主要是由于 pnpm 很好的解决了 npm 与 yarn 遗留的历史问题。
4.1. 安装依赖提速
pnpm 分三个阶段执行安装:
- 依赖解析。 仓库中没有的依赖都被识别并获取到仓库。
- 目录结构计算。
node_modules目录结构是根据依赖计算出来的。 - 链接依赖项。 所有以前安装过的依赖项都会直接从仓库中获取并链接到
node_modules。
4.2. pnpm 硬连接 & 软链接
硬链接hard link(节省磁盘空间): 电脑文件系统中的多个文件平等的共享同一个文件存储单元。
软链接sybolic link(符号连接): 包含一条以绝对路径或相对路径的形式指向其他文件或者目录的引用。
4.3. pnpm 相比于 npm 与 yarn 包管理工具的优势
- 速度快:多数场景下,安装速度是
npm/yarn的 2 - 3 倍。 - 基于内容寻址:硬链接节约磁盘空间,不会重复安装同一个包,对于同一个包的不同版本采取增量写入新文件的策略。
- 依赖访问安全性强:优化了
node_modules的扁平结构,提供了限制依赖的非法访问(幽灵依赖) 的手段。 - 支持
monorepo:自身能力就对monorepo工程模式提供了有力的支持。在轻量场景下,无需集成 lerna、Turborepo 等工具。
默认情况下禁止幽灵依赖,是 pnpm 基于软链接的依赖管理模式带来的好处。
pnpm 的依赖文件结构与 package.json 中的声明保持一致。因此,我们将不能再访问 package.json 中未声明的包。 这解决了 npm / yarn 一直依赖的幽灵依赖问题,提升了依赖访问的安全性。
5. Monorepo 项目结构
6. 相关文档链接
1. lerna 还是 pnpm + changesets?monorepo 工具核心就看这三个功能
3. [译]用 PNPM Workspaces 替换 Lerna + Yarn
7. FAQ
7.1. 幽灵依赖
基于 npm/yarn 的 Monorepo 方案,依然存在 “幽灵依赖” 问题,我们可以通过 pnpm 彻底解决这个问题
npm/yarn 安装依赖时,存在依赖提升,某个项目使用的依赖,并没有在其 package.json 中声明,也可以直接使用,这种现象称之为 “幽灵依赖”;随着项目迭代,这个依赖不再被其他项目使用,不再被安装,使用幽灵依赖的项目,会因为无法找到依赖而报错。