什么是MonoRepo
Monorepo 是一种项目代码管理方式,指单个仓库中管理多个项目,有助于简化代码共享、版本控制、构建和部署等方面的复杂性,并提供更好的可重用性和协作性。Monorepo 提倡了开放、透明、共享的组织文化,这种方法已经被很多大型公司广泛使用,如 Google、Facebook 和 Microsoft 等。
项目架构演进
阶段一:单仓库巨石应用, 一个 Git 仓库维护着项目代码,随着迭代业务复杂度的提升,项目代码会变得越来越多,越来越复杂,大量代码构建效率也会降低,最终导致了单体巨石应用,这种代码管理方式称之为 Monolith。
阶段二:多仓库多模块应用,于是将项目拆解成多个业务模块,并在多个 Git 仓库管理,模块解耦,降低了巨石应用的复杂度,每个模块都可以独立编码、测试、发版,代码管理变得简化,构建效率也得以提升,这种代码管理方式称之为 MultiRepo。
阶段三:单仓库多模块应用,随着业务复杂度的提升,模块仓库越来越多,MultiRepo这种方式虽然从业务上解耦了,但增加了项目工程管理的难度,随着模块仓库达到一定数量级,会有几个问题:跨仓库代码难共享;分散在单仓库的模块依赖管理复杂(底层模块升级后,其他上层依赖需要及时更新,否则有问题);增加了构建耗时。于是将多个项目集成到一个仓库下,共享工程配置,同时又快捷地共享模块代码,成为趋势,这种代码管理方式称之为 MonoRepo。
MonoRepo的优缺点
| 场景 | MultiRepo | MonoRepo |
|---|---|---|
| 代码可见性 | ✅ 代码隔离,研发者只需关注自己负责的仓库 ❌ 包管理按照各自owner划分,当出现问题时,需要到依赖包中进行判断并解决。 | ✅ 一个仓库中多个相关项目,很容易看到整个代码库的变化趋势,更好的团队协作。 ❌ 增加了非owner改动代码的风险 |
| 依赖管理 | ❌ 多个仓库都有自己的 node_modules,存在依赖重复安装情况,占用磁盘内存大。 | ✅ 多项目代码都在一个仓库中,相同版本依赖提升到顶层只安装一次,节省磁盘内存, |
| 代码权限 | ✅ 各项目单独仓库,不会出现代码被误改的情况,单个项目出现问题不会影响其他项目。 | ❌ 多个项目代码都在一个仓库中,没有项目粒度的权限管控,一个项目出问题,可能影响所有项目。 |
| 开发迭代 | ✅ 仓库体积小,模块划分清晰,可维护性强。 ❌ 多仓库来回切换(编辑器及命令行),项目多的话效率很低。多仓库见存在依赖时,需要手动 npm link,操作繁琐。 ❌ 依赖管理不便,多个依赖可能在多个仓库中存在不同版本,重复安装,npm link 时不同项目的依赖会存在冲突。 | ✅ 多个项目都在一个仓库中,可看到相关项目全貌,编码非常方便。 ✅ 代码复用高,方便进行代码重构。 ❌ 多项目在一个仓库中,代码体积多大几个 G,git clone时间较长。 ✅ 依赖调试方便,依赖包迭代场景下,借助工具自动 npm link,直接使用最新版本依赖,简化了操作流程。 |
| 工程配置 | ❌ 各项目构建、打包、代码校验都各自维护,不一致时会导致代码差异或构建差异。 | ✅ 多项目在一个仓库,工程配置一致,代码质量标准及风格也很容易一致。 |
| 构建部署 | ❌ 多个项目间存在依赖,部署时需要手动到不同的仓库根据先后顺序去修改版本及进行部署,操作繁琐效率低。 | ✅ 构建性 Monorepo 工具可以配置依赖项目的构建优先级,可以实现一次命令完成所有的部署。 |
小型项目实践 pnpm+workspace 改造
改造前巨石项目架构
├─README.md
├─questionnaire-mock
| ├─index.js
| ├─package.json
| ├─pnpm-lock.yaml
| ├─mock
| | ├─index.js
| | ├─module
| | | ├─question.js
| | | └test.js
| | ├─data
| | | └getQuestionList.js
├─questionnaire-fe
| ├─.babelrc
| ├─.eslintrc.js
| ├─.prettierrc.js
| ├─README.md
| ├─commitlint.config.js
| ├─craco.config.js
| ├─package-lock.json
| ├─package.json
| ├─pnpm-lock.yaml
| ├─tsconfig.json
| ├─src
| ├─public
| | ├─favicon.ico
| | ├─index.html
| | └manifest.json
| ├─.husky
| | ├─commit-msg
| | └pre-commit
改造后MonoRepo项目架构
├─README.md
├─package.json
├─pnpm-lock.yaml
├─pnpm-workspace.yaml
├─packages
| ├─questionnaire-mock
| | ├─index.js
| | ├─package.json
| | ├─pnpm-lock.yaml
| | ├─mock
| | | ├─index.js
| | | ├─module
| | | | ├─question.js
| | | | └test.js
| | | ├─data
| | | | └getQuestionList.js
| ├─questionnaire-fe
| | ├─.babelrc
| | ├─.eslintrc.js
| | ├─.prettierrc.js
| | ├─README.md
| | ├─commitlint.config.js
| | ├─craco.config.js
| | ├─package-lock.json
| | ├─package.json
| | ├─pnpm-lock.yaml
| | ├─tsconfig.json
| | ├─src
| | ├─public
| | | ├─favicon.ico
| | | ├─index.html
| | | └manifest.json
改造的项目地址:gitee.com/IndulgeBack/react-questionnaire