《全栈Monorepo开发实战》阅读笔记(1)

168 阅读6分钟

前言

  该笔记主要是基于《全栈Monorepo开发实战》这本书的一个阅读和实践记录,适合对使用TypeScript实现Monorepo项目感兴趣以及计划在项目中实践Monorepo项目的前端开发工程师,需要了解更细节的内容可以自行去找这本书来阅读。

实战中涉及到的技术栈:Vue3+Fastify+Deno+pnpm

第1章 Monorepo架构

简介

   Monorepo的诞生可以追溯到2000年初,mono指的是single,即单;repo就是repository,即仓库;虽然mono是single的含义,但与Single-repo的区别是,Single-repo指的是一个代码仓库只有一个项目,而Monorepo是一个代码仓库管理了多个项目。

   谷歌是最早实现Monorepo架构的公司之一,也是世界最大的Monorepo仓库之一,有20亿行代码,每天有数万名工程师进行40000+次提交

   2022年JavaScript年度调研报告里首次出现Monorepo管理/构建工具排行榜,可以从JavaScript GitHub的Star年度涨幅排行榜中看到很多影响力非常高的开源项目开始使用Monorepo架构管理代码,例如Vite、React、Vue3、Babel、Next、Nuxt等。

1.1 常用的代码组织架构

1. Single-repo

   即一个应用的所有代码全放在一个代码仓库中管理,模块之间仅仅通过简单的划分或划分来进行组织,例如在项目中常见的分模块目录结构:Lib、Utils、View。

   这种项目通常会随着业务的不断扩展和迭代,逐渐形成Monolith(巨石)应用,整个应用就像一个独立的npm包,只在根目录有一个package.json文件,用来管理项目的版本和依赖关系。例如Vue2项目就是一个由Yarn管理的Single-repo项目,目录结构如下:

vue
├── src
│   ├── compiler
│   ├── core
│   ├── server
│   ├── share
│   └── platforms
...
└── package.json

2. Multirepo

   即多代码仓库,是一种把应用内的各模块进行单独隔离和封装的方法,每个模块都存放在独立的代码仓库中进行管理。相当于在Single-repo的基础上,将公共模块放在单独的代码仓库进行隔离和发布,例如Util库、UI库和Cli库等,每个模块都有一个代码仓库和对应的package.json进行包的管理。

每个代码仓库都有独立的版本号管理,依赖管理、CI/CD流程。优点如下:

  • 与项目进行解耦
  • 可单独发布提供给多个项目使用
  • 便于模块的单独管理和维护

3. Monorepo

   Monorepo相当于是在Single-repo上实现Multrepo的优点和特性,即Monorepo项目中的各个子项目与Multirepo一样,进行彻底的隔离和封装,但是只需要在同一个仓库中进行管理。

例如Vue3就是一个由pnpm管理的Monorepo项目,其目录结构如下:

vue/core
├── packages
│   ├── compiler
|   |   | ...
|   |   └── package.json
│   ├── compiler-dom
|   |   | ...
|   |   └── package.json
│   ├── vue
|   |   | ...
|   |   └── package.json
...
│   ├── package.json
└── pnpm-workspace.yaml

   packages目录下的每一个目录都是一个完备的npm包,并且统一进行版本管理。

🔑 代码架构对照表

仓库架构Single-repoMultirepoMonorepo
Repo数量一个多个一个
package.json数量一个一个仓库一个工作空间目录一个,一个模块一个

Monorepo的优缺点

1. 有助于更好、更高效的工作流程

这种可见性使开发者更容易地进行跨系统、应用程序、库的程序搜索、共享和代码复用。随着代码复用和可见性的提高,代码一致性也会提高。

2.更容易管理应用内部之间的依赖关系

Monorepo由多个应用程序和库组成,这种组织方式可以更好地检查包之间的关系,更容易地进行全局重构。例如将A项目中的函数移动到B库中,或者将B库拆分成若干小库。这些操作只需要在IDE中移动目录,修改错误并调试即可完成。但缺点也是很明显,需要对项目涉及的所有方面有足够了解,一般不建议这么操作,即不轻易地修改存量代码,否则可能造成不可预期地损失。

3. 提供统一的Git提交视图

Monorepo项目中,由于所有提交在同一个仓库中,因此更容易分析当前应用整体Git提交情况。

4. 便于统一CI/CD、打包等自动化构建和测试流水线

Monorepo的优势在于将所有代码放在一起,有利于进行测试自动化。由于代码、工具和配置都在一起,可以更容易地统一管理所有配置信息,比散落在多个仓库中的配置文件更容易维护。

5. 可以极大简化依赖的管理

当项目变复杂时,非常清晰的单一模块依赖已经变得不那么重要,更重要的是在全局上统一管理依赖关系。

6. 降低多技术融合的成本

Monorepo支持多种流行技术,并且可以很容易地进行融合,例如一个pnpm项目中是可以集成Rust workspace或者Go workspace项目。使用Rust编写CLI,再通过pnpm发布,其他项目使用起来会变得非常简单。

Monorepo的缺点

1. 相关开发工具不成熟

Monorepo是近年流行起来的一种开发方式,相关工具链和IDE仍在适应和调整阶段。Git在处理大型Monorepo项目时的性能也不尽如人意。

2. CI/CD流水线较为复杂

由于有太多项目依赖的包和模块,构建需要太多的步骤,可能导致迭代停滞不前。任何改动都需要重新构建整个Monorepo项目,而不是只构建应用程序的一部分。需要深入了解代码库之间的关系,并编写自动化流程。

3. 测试复杂

测试和通常的构建/编译任务必须按照正确的顺序完成,才能确保所有依赖项从正确的来源构建并在正确的时间可用。

4. 固有的复杂性

管理Monorepo项目非常复杂,需要解决很多问题,而且容易出错。定制协调和自动化脚本需要花费相当长的时间去学习使用。

5. 权限的管理性差

因为如Git或Mercurial等系统缺少内置目录权限。通常需要在一个目录下面维护一个Markown文档来指明负责人。