Monorepo
多包管理
目前,最常见的多包管理方案有两种:
- 多仓管理(Multirepo):一个包对应一个仓库,多个包对应多个仓库。
- 单仓管理(Monorepo):无论是一个包还是多个包,都对应一个仓库。
Monorepo
就前端而言,一个仓库一个项目的管理方式存在诸多弊端:
- 每个项目都要搭建 eslint + prettier + commitLint + styleLint 等代码规范校验。
- 每个项目都要搭建许多类似的常用组件和创建公共 utils 函数。
- 每个项目的主要依赖库(Vue、React)版本可能不一致,且存在重复安装。
- 有时候组件改动会涉及到多个项目都要手动更改。
Monorepo 可以让多个模块共享同一个仓库,因而它们可以共享同一套构建流程、代码规范也可以做到统一,特别是如果存在模块间有共享公共组件的情况,查看代码、修改 bug、调试等会更加方便。
- 统一的依赖管理。
- 简化代码共享。
- 更容易进行跨项目更改。
- 更好的跨团队协作。
知名公司使用Monorepo案例
- 谷歌(Google):谷歌是使用 Monorepo 的著名代表之一。他们将所有项目和库存储在一个称为 Piper 的庞大代码库中。这使得他们能够更容易地管理依赖关系、共享代码并跨项目进行更改。
- Meta:Meta 也采用了 Monorepo 策略。他们的代码库包括了多个项目,如 React、React Native 和 Jest 等。这有助于他们统一管理这些项目的代码和依赖关系。
- 微软(Microsoft):虽然微软在某些方面使用多代码库策略,但在一些项目中也采用的 Monorepo 仓库策略。例如,Windows 操作系统和 Visual Studio 代码编辑器都使用 Monorepo 进行管理。
- Twitter:Twitter 也是 Monorepo 的支持者,他们将所有代码存储在一个称为 Pants 的代码库中。这有助于他们更好地管理依赖关系和提高代码复用率。
- Uber:Uber 使用一个名为 Fusion.js 的 Monorepo 代码库来管理他们的许多前端项目。这使他们能够更有效地共享代码和跨项目进行更改。
在企业开发中,如果使用 Monorepo 架构来管理多个项目,通常是将公共的组件、工具库、api 等抽离出来进行共享:
当然,Monorepo也存在一些缺点,例如:
- 代码库规模较大。
- 缺乏独立版本控制。
- 权限和安全性问题。
- 工具和基础设施要求。
并非所有的项目都适合使用Monorepo,在使用之前,需要进行一定的考量。以下场景非常适合使用:
- 项目之间有很多共享代码和资源的时候。
- 当团队需要进行跨项目协作的时候。
- 统一多个包的依赖非常重要的时候。
Multirepo
Multirepo,即多仓库,就是不同项目和库存储在各自独立的代码库中的策略。
由于是独立的项目和独立仓库,使其在版本控制、代码库规模、安全性上有更好的控制。
| 功能 | Monorepo | Multirepo |
|---|---|---|
| 开发 | 只需要在一个仓库中开发 | 仓库体积小,模块划分清晰 |
| 复用 | 代码复用高,方便进行代码重构 | 需要多个仓库来回切换,无法实现跨项目代码复用 |
| 工程配置 | 所有项目统一使用相同配置 | 各个项目可能有一套单独标准 |
| 依赖管理 | 共同依赖可提升至 root,版本控制更加容易,依赖管理更加方便 | 不同项目中会存在相同的依赖,并且依赖会存在版本不同的情况 |
| 代码管理 | 代码全在一个仓库,项目太大用 Git 管理会存在问题,无法隔离项目代码权限 | 各个团队可以控制代码权限,也几乎不会有项目太大的问题 |
Workspace
工作空间可以看作是一个共享的区域,所有用于工作的资源都可以从这个区域获取到。
在软件开发中,工作空间通常指一个用于组织和管理项目文件、资源和工具的逻辑容器。它通常是一个文件夹结构,用于将相关的项目文件、代码、设置和其他资源集中放置在一起。
工作空间的概念在不同的编程语言和开发工具中可能略有不同,但其基本目标都是提供一个集中式环境,以帮助开发者管理和协同开发多个项目。主要功能包括:
- 组织和管理项目文件。
- 跨项目共享设置和工具。
- 支持协同开发。
pnpm工作空间
在 pnpm 中,工作空间就是一个管理多个包的环境,它通过独特的依赖管理方式极大地提高了效率。pnpm 的工作空间支持符号链接和硬链接机制,使得不同包之间能够高效地共享依赖,同时保证每个包的独立性。
pnpm 的工作空间为大型 Monorepo 项目提供了一个强大而灵活的开发环境,使得管理和开发多个包变得更加简单和高效。
定义工作空间
在根目录创建一个 pnpm-workspace.yaml 的文件,该文件用于定义哪些包会被包含在 workspace 工作空间中,默认情况下,所有子目录下的所有包都会被包含在 workspace 里面。
packages:
# packages/ 下所有子包,但是不包括子包下面的包
- 'packages/*'
# components/ 下所有的包,包含子包下面的子包
- 'components/**'
# 排除 test 目录
- '!**/test/**'
Monorepo搭建
// 初始化
pnpm init
// 创建workspace文件
touch pnpm-workspace.yaml
// 将包安装到工作空间
pnpm add <包名> --workspace-root
// pnpm add <包名> -w
// 安装工作空间的一个包到工作空间另一个包里面
// 该命令表示将 B 包安装到 A 包里面,也就是说 B 包成为了 A 包的一个依赖。
// 其中 B 包后面的 --workspace 参数表示该包来自于工作空间,而非 npm 远程仓库,--filter 表示安装到 A 包里面。
pnpm add <包名B> --workspace --filter <包名A>