MultiRepo 和 Monorepo:代码管理的演进与选择

一、Monorepo 介绍

Monorepo 是一种项目代码管理方式,指单个仓库中管理多个项目,有助于简化代码共享、版本控制、构建和部署等方面的复杂性,并提供更好的可重用性和协作性。Monorepo 提倡了开放、透明、共享的组织文化。

二、Monorepo 演进

阶段一:单仓库巨石应用, 一个 Git 仓库维护着项目代码,随着迭代业务复杂度的提升,项目代码会变得越来越多,越来越复杂,大量代码构建效率也会降低,最终导致了单体巨石应用,这种代码管理方式称之为 Monolith

阶段二:多仓库多模块应用 ,将项目拆解成多个业务模块,并在多个 Git 仓库管理,模块解耦,降低了巨石应用的复杂度,每个模块都可以独立编码、测试、发版,代码管理变得简化,构建效率也得以提升,这种代码管理方式称之为 MultiRepo-Multi Repository。

阶段三:单仓库多模块应用 ,随着业务复杂度的提升,模块仓库越来越多,MultiRepo这种方式虽然从业务上解耦了,但增加了项目工程管理的难度,随着模块仓库达到一定数量级,会有几个问题:跨仓库代码难共享;分散在单仓库的模块依赖管理复杂(底层模块升级后,其他上层依赖需要及时更新,否则有问题);增加了构建耗时。于是将多个项目集成到一个仓库下,共享工程配置,同时又快捷地共享模块代码,成为趋势,这种代码管理方式称之为 MonoRepo-Mono Repository。

三、Monorepo 项目管理策略对比

场景 Monolithic 架构 MultiRepo多仓库多模块应用 MonoRepo单仓库多模块应用
代码共享 ✅ 编码方便、代码复用度高❌ 项目增多后,启动十分缓慢,开发效率降低,调试成本较高 ✅ 代码隔离,开发者只需关注自己负责的仓库 ❌ 代码复用能力差。各项目独立管理,代码很难共享,存在重复造轮子的问题。可以使用包管理平台(如 npm)或 模块联邦实现,较复杂。 ✅ 一个仓库中多个相关项目,很容易看到整个代码库的变化趋势。✅ 启动快速,调试方便✅ 代码共享比较容易(直接使用工作区 workspace)
依赖管理 ✅ 统一的工程配置,新项目可以直接进入开发,无需复杂的工程配置 ❌ 多个仓库都有自己的 node_modules,存在依赖重复安装情况,占用磁盘内存大。 ✅ 统一的工程配置,多项目代码都在一个仓库中,相同版本依赖提升到顶层只安装一次,节省磁盘内存,
开发迭代 ❌ 代码体积庞大,不利于阅读和重构 ✅ 仓库体积小,模块划分清晰,可维护性强。 ❌ 多仓库来回切换(编辑器及命令行),项目多的话效率很低。 ✅ 代码复用高。❌ 多项目在一个仓库中,代码体积较大,git clone时间较长。 ✅ 依赖调试方便,依赖包迭代场景下,借助工具自动 npm link,直接使用最新版本依赖,简化了操作流程。
工程配置 ✅ 各项目的依赖版本统一❌ 依赖升级困难,所有项目都使用同一依赖,升级的成本、风险很高。 ✅ 单个项目升级依赖不会影响到其他项目❌ 各项目构建、打包、代码校验都各自维护,不一致时会导致代码差异或构建差异。 ✅ 各项目依赖版本可以统一,也可以保持不同,相当灵活。 共同依赖可以提升到 root,方便依赖管理✅ 便于统一批量升级各项目依赖
构建部署 ❌ 项目增多后,构建、部署速度变得越来越慢 ✅ 单独的部署环境 ✅ 各项目可以单独部署

四、 如何选择?

3.1 适合使用 MultiRepo (仓库多模块应用) 的场景

  1. 模块独立性强

    • 模块之间几乎没有依赖关系,或者依赖关系很弱。
    • 每个模块可以独立开发、测试和部署。
  2. 团队规模大

    • 不同的团队负责不同的模块,团队之间的协作较少。
    • 需要对模块设置严格的权限管理。
  3. 技术栈多样性

    • 不同模块使用了不同的技术栈。

3.2 适合使用 MonoRepo (单仓库多模块应用) 的场景

  1. 模块依赖关系强

    • 模块之间共享大量代码或依赖。
    • 跨模块的变更较多,需要统一管理。
  2. 团队规模小到中型

    • 团队规模较小,成员需要频繁协作。
    • 权限管理需求较低。
  3. 统一的技术栈

    • 所有模块使用相同的技术栈(如前端所有模块使用 Vue 或 React)。
  4. 需要高效的开发和测试

    • 希望通过统一的工具链和依赖管理提升开发效率。
    • 希望通过增量构建和测试优化 CI/CD 流程。

五、Monorepo 的一些问题

1、幽灵依赖

问题:npm/yarn 安装依赖时,存在依赖提升,某个项目使用的依赖,并没有在其 package.json 中声明,也可以直接使用,这种现象称之为 "幽灵依赖";随着项目迭代,这个依赖不再被其他项目使用,不再被安装,使用幽灵依赖的项目,会因为无法找到依赖而报错。

方案 :基于 npm/yarn 的 Monorepo 方案,依然存在 "幽灵依赖" 问题,我们可以通过 pnpm 彻底解决这个问题

2、依赖安装耗时长

问题 :MonoRepo 中每个项目都有自己的 package.json 依赖列表,随着 MonoRepo 中依赖总数的增长,每次 install 时,耗时会较长。

方案 :相同版本依赖提升到 Monorepo 根目录下,减少冗余依赖安装;使用 pnpm 按需安装及依赖缓存。

六、工程搭建 pnpm+workspace+vite+ts+vue

采用MonoRepo管理单仓库多模块应用的方式,结合pnpm、Vite、Vuet和TypeScript的技术栈,可以形成一个高效、模块化和现代化的前端项目。以下是项目的整体设计方案:

1、项目背景

XXX项目X年前搭建采用单仓库巨石应用Monolith, 一个 Git 仓库维护着项目代码,随着迭代业务复杂度的提升,项目代码会变得越来越多,越来越复杂,大量代码构建效率也会降低,最终导致了单体巨石应用

面临着陈旧的架构和过时的组件库,任何微小的升级都可能引发全局性的影响。新技术和功能的应用受限,维护困难,且无法实现有效的统一管理。这些问题都迫切需要我们进行系统的重构。

XXXXX现状分析:

痛点 分析 方案
**单仓库巨石应用(Monolith)&&**多仓库多模块应用 所有的前端代码都维护在一个工程中,随着时间的推移和业务的增长,代码基础变得庞大和复杂。尽管目前用了iframe的方式,多仓库多模块应用**,**但是iframe嵌入的模块都散落在各个git仓库,难以维护,公共模块也难以公用。 MonoRepo方案
技术栈老旧 项目采用的是Vue2技术栈,但使用了老旧的架构和过时的组件库,这限制了新技术的采用和现有功能的扩展。 每个模块单独部署构建,按需应用自己模块的版本
代码维护困难 历史代码中缺乏规范的TypeScript写法,使得类型系统的优势没有得到充分发挥,增加了维护难度和出错概率。 MonoRepo方案

升级的必要性:

| 提升点 | 分析 |
|--------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---|
| 单仓库多模块应用 | 随着业务复杂度的提升,模块仓库越来越多,MultiRepo这种方式虽然从业务上解耦了,但增加了项目工程管理的难度,随着模块仓库达到一定数量级,会有几个问题:跨仓库代码难共享;分散在单仓库的模块依赖管理复杂(底层模块升级后,其他上层依赖需要及时更新,否则有问题);增加了构建耗时。于是将多个项目集成到一个仓库下,共享工程配置,同时又快捷地共享模块代码,成为趋势,这种代码管理方式称之为 MonoRepo-Mono Repository。 |
| 提高构建效率 | 现有的单体应用构建效率低下,需要通过模块化和微前端技术将应用拆分,实现更快的构建和部署。 |
| 技术栈现代化 | 更新到最新的Vue版本,采用最新的前端技术和工具,以便更好地应对未来业务的需求和挑战。 |
| 代码质量提升 | 通过引入更严格的TypeScript规范和代码规范工具(如ESLint、Prettier),提升代码质量,减少bug发生率。 |
| 用户体验优化 | 通过性能优化措施(如代码分割、懒加载、资源优化等)改善页面加载速度和交互平滑度,提升用户体验。 | |

2、项目范围和目标

解决XXXX项目中历史逻辑混乱、技术栈老旧等问题, 缩短XXXXX项目整体需求交付时长。

简化代码共享、版本控制、构建和部署等方面的复杂性,并提供更好的可重用性和协作性。

建设一个统一工程建设标准、促进跨项目代码复用、从而实现开发效率提升、减少维护成本与简化项目管理、高效、稳定、可持续发展的系统,为后续业务发展和技术架构升级打下基础,具体目标可分为:

  1. 提高人效
  2. 提高加载性能
  3. 提高稳定性
  4. 可维护可扩展性
相关推荐
李明卫杭州3 分钟前
Sass颜色函数介绍
前端
未来之窗软件服务4 分钟前
企业自动化交互体系的技术架构与实现:从智能回复到自动评论—仙盟创梦IDE
架构·自动化·交互·仙盟创梦ide·东方仙盟
开开心心就好6 分钟前
专业鼠标点击器,自定义间隔次数
javascript·安全·计算机外设·excel·音视频·模拟退火算法
pe7er12 分钟前
使用CDN、ImportMap增强Vue playground
前端
ze_juejin22 分钟前
Angular的懒加载由浅入深
前端
JSON_L23 分钟前
Vue 详情模块 4
前端·javascript·vue.js
码间舞29 分钟前
什么是Tearing?为什么React的并发渲染可能会有Tearing?
前端·react.js
gnip40 分钟前
做个交通信号灯特效
前端·javascript
小小小小宇41 分钟前
Webpack optimization
前端
文火冰糖的硅基工坊42 分钟前
[硬件电路-123]:模拟电路 - 信号处理电路 - 常见的高速运放芯片、典型电路、电路实施注意事项
嵌入式硬件·架构·信号处理·电路·跨学科融合