初识Monorepo

news2024/11/24 7:17:46

026d5ae6e3ea178bd2ffdaecffec9566.png

引言

在如今快节奏的前端开发中,管理多个项目和组件的复杂性成为了开发团队的挑战,Monorepo(单一代码仓库)作为一种新兴的解决方案,正在成为开发团队的新宠。

Monorepo简介

是什么

Monorepo 是一种软件开发的策略模式,它代表"单一代码仓库"(Monolithic Repository)。在 Monorepo 模式中,所有相关的项目和组件都被存储在一个统一的代码仓库中,而不是分散在多个独立的代码仓库中。

简单理解:所有的项目在一个代码仓库中,但并不是说代码没有组织的都放在 ./src 文件夹里面。

谁在用

  • 大型互联网公司:Google、Facebook、Uber、MicroSoft、阿里、字节等

  • 前端常用的开源库:Vue、React、Vite、Babel、Element-plus

为什么会出现

Monorepo的出现是为了解决传统分离式代码仓库所面临的一些挑战和痛点,我们先来看看代码管理的发展历程:

1、Single-repo Monolith时期

单一代码仓库:传统的单体式应用程序通常将所有的功能和模块打包在一起,形成一个单一的代码库和部署单元。这种单一的代码库包含了应用程序的所有部分,从前端界面到后端逻辑,甚至包括数据库模式和配置文件等。

├── client/
│   ├── src/
│   │   ├── components/
│   │   ├── pages/
│   │   ├── services/
│   │   ├── utils/
│   │   ├── App.js
│   │   └── index.js
├── server/
│   ├── controllers/
│   ├── models/
│   ├── routes/
│   ├── config/
│   └── app.js
├── tests/
│   ├── client/
│   └── server/
├── package.json
├── README.md
└── ...

存在问题:

  • 难以实现部分更新和独立扩展的灵活性

  • 高度耦合,代码臃肿

2、Multi-repo时期

多代码仓库:将不同的功能模块、组件或服务等分别存放在独立的仓库中,可以单独进行版本控制、构建、部署和发布,使得不同的团队或开发者可以独立地开发、测试和维护各自的模块,更容易实现并行开发和团队协作。

// Repository - module1

├── node_modules/
├── src/
│   ├── components/
│   ├── pages/
│   ├── utils/
│   ├── App.js
│   └── index.js
├── styles/
│   ├── main.css
├── public/
│   ├── index.html
├── package.json
└── ...

// Repository - module2

├── node_modules/
├── src/
│   ├── components/
│   ├── pages/
│   ├── utils/
│   ├── App.js
│   └── index.js
├── styles/
│   ├── main.css
├── public/
│   ├── index.html
├── package.json
└── ...

// Repository - lib

├── node_modules/
├── package.json
├── src
│   ├── ...
├── README.md

// 共享代码
- lib 进行发包,比如包名为 @my-scope/lib
- 进入project1 或 project2 进行npm install
- 在代码中引入
 import {method} from '@my-scope/lib';

存在问题:

  • 跨仓库开发:多仓维护成本高,

  • 开发调试:npm包(修改->发布->安装成本高),调试麻烦(npm link),

  • 版本管理:依赖版本同步升级管理麻烦

  • 项目基建:脚手架升级,新老项目规范很难保证统一

3、Monorepo时期

可以解决上述问题,代码之间的共享也不再强依赖于NPM来进行,既保留了Single-repo 单仓环境维护的便利性,同时满足Multi-repo 多仓对于项目解耦的独立开发管理。

├── packages/
│   ├── module1/
│   │   ├── src/
│   │   ├── tests/
│   │   ├── package.json
│   │   └── ...
│   ├── module2/
│   │   ├── src/
│   │   ├── tests/
│   │   ├── package.json
│   │   └── ...
│   └── shared/
│       ├── src/
│       ├── tests/
│       ├── package.json
│       └── ...
├── libs/
│   ├── lib1/
│   │   ├── src/
│   │   ├── tests/
│   │   ├── package.json
│   │   └── ...
│   ├── lib2/
│   │   ├── src/
│   │   ├── tests/
│   │   ├── package.json
│   │   └── ...
│   └── ...
├── docs/
├── .gitignore
├── package.json
└── ...

哎呀,这项目组织看起来太简单了!!!就是把各个项目放到一个文件夹下了嘛,但是我们尝试以下思考:

1. 怎样进行项目间代码共享?发包至npm再引用安装吗?

答案:肯定不是的,举个例子:

  • 假设 lib 的包名为 @my-scope/lib,无需发包至NPM。

  • 在一级目录的 package.json 添加包名 @my-scope/lib: "workspace:*"。

  • 在两个 projects 中的代码中引入:

import {method} from '@my-scope/lib';

2. 各个项目怎么装包、运行?切换目录挨个装、挨个运行吗?(那岂不太麻烦了)

答案:在根目录下就可以给各个项目安装。

3. 各个项目代码开发完分别提交一次commit,还是一起提交呢?

答案:可以一起提交。

4. lib包还能单独发布npm 包吗?

答案:可以。

5. 编译构建的顺序要我们自己定吗?

答案:不同的Monorepo库不同的处理方式,有些需要自己指定构建顺序,有些会内置判断项目依赖关系,无需自定义构建顺序。

怎么用

Monorepo 有很多优势,但要发挥作用,需要拥有合适的框架,帮助我们保持快速、易于理解和管理。

Monorepo 策略

Monorepo策略期望框架能提供以下的功能:

功能详细介绍可参考https://monorepo.tools/#workspace-analysis6afd956104c17e03ccc9feb51c972ceb.png

但是理想是丰满的,现实是骨感的。

目前前端领域的 Monorepo 生态的显著特点是只有库,而没有大一统的框架或者完整的构建系统来支持。

现有Monorepo库:

Bazel(谷歌)、   Gradle Build Tool(Gradle, Inc)、   Lage(微软)、   Lerna、  Nx(Nrwl)、  Pants(Pants Build 社区)、  Rush(由 Microsoft)和 Turborepo(由 Vercel)

79c96fdae6f11c21917a829be620ce30.png
各个库目前所支持的功能

生态社区中Nx,Lerna,Turborepo脱颖而出。

Monorepo生态

核心技术

包管理方案:npm、yarn、pnpm

包版本方案:Lerna、Changesets

包构建方案:Turborepo、Nx

辅助技术

代码规范工具:Eslint、Prettier

提交规范工具:Commitlint、Commitizen

Monorepo实战

1. pnpm Workspace

自带Monorepo的解决方案

官网:https://pnpm.io/workspaces

  • 全局安装pnpm

npm install -g pnpm
  • 在项目根目录下创建一个package.json文件,并设置"private": true以表示该项目是私有的。

  • 在package.json文件中添加一个"workspaces"字段,并设置为一个包含子项目目录的数组。例如

"workspaces": [
  "packages/*"
]
  • 可以新建两个vue项目,在每个子项目的目录下,都有一个独立package.json文件

  • 所有工作空间安装依赖:在根目录下运行pnpm install命令,它会自动安装所有子项目的依赖

pnpm install
  • 全局的公共依赖包

pnpm install react -w
pnpm install rollup -wD 安装开发依赖
  • 给某个子项目单独安装指定依赖

pnpm 提供了 --filter 参数

pnpm add axios --filter @package1
  • 模块之间的相互依赖

pnpm install @package2 -r --filter @package1

在设置依赖版本的时候推荐用 workspace:* ,这样就可以保持依赖的版本是工作空间里最新版本,不需要每次手动更新依赖版本。

pnpm workspace 谁在用:vue, vite等。

pnpm Monorepo优点:

  1. 天然支持Monorepo(在根目录给所有空间安装依赖、在根目录单独给子包安装依赖)

缺点:

  1. 需要手动提升公共依赖。

  2. 需要手动指定任务(dev,build)执行,任务不支持并行执行,影响构建速度。

  3. 不支持自动版本控制,需要依赖第三方工具,官方推荐两个工具changesets、Rush。

  4. 没有通用的脚手架模板。

  5. 不支持缓存。

  6. 不支持依赖分析。

...

2. Lerna

目前已经交给Nx 公司。

官网:https://lerna.js.org/

  • 默认npm,支持yarn,pnpm

  • 克隆下官方demo

git clone https://github.com/lerna/getting-started-example.git
cd getting-started-example
npm install
  • 初始化

npx lerna@latest init
  • 工作区可视化,能形象看到项目之间依赖关系图

npx nx graph
f14ffaf8a058d2262daf589d05ff22ac.png
项目依赖关系图
  • 公共包提升根目录

lerna bootstrap --hoist
  • 构建所有项目(自动识别build并以正确的顺序构建)

npx lerna run build
  • 给某个package单独build,使用--scope

npx lerna run build --scope=package1
  • 开启缓存

npx lerna add-caching
  • 自带版本控制

lerna publish --no-private (过滤私有包,不发布)
  • 添加子项目,lerna内置了一些项目模版,例如react

lerna create <pkgName>

优点:

  1. 依赖自动提升

  2. 交给Nx公司之后,支持开启缓存、内部依赖分析、任务分析

  3. 检测改动commit影响的包,区分提示

  4. 自带版本控制(能分析出 private:false 的包,引导版本号提升)

缺点:

  1. 默认npm, npm@7版本以下不支持Monorepo,只能安装根目录的依赖,需要使用 lerna bootstrap --hoist,@npm@7版本以上支持,可以直接npm安装所有子包的依赖

3. Turborepo

官网:https://turbo.build/,官方有详细的demo,这里就不赘述。核心的功能点如下:

  • 包管理:支持npm,yarn,pnpm

  • turbo运行任务 turbo hello,它必须在turbo.json

{
  "pipeline": {
    "build": {
      //   ^^^^^
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "lint": {},
    "dev": {
      //   ^^^
      "cache": false
    }
  }
}
  • 默认使用缓存

  • 自动识别项目中的 dev, build 命令,并全量运行

turbo build
  • 仅运行某个单独的包,使用--filter

turbo dev --filter package1

优点:

  • 多任务并行处理

  • 云缓存:多人开发共享缓存

  • 任务管道

  • 约定配置:显式声明,执行顺序

缺点:

  • 版本控制不支持,官方推荐Changesets

思考

什么场景适合用

  1. 代码共享:当多个项目或模块之间需要共享代码、组件或工具库时。

  2. 统一版本管理:需要统一管理各个项目的版本依赖,确保一致性。

  3. 简化依赖管理:减少依赖安装和版本冲突,提高构建和部署效率。

  4. 协作与团队工作:团队成员可以更轻松地共享代码、协作开发和进行代码审查。

  5. 简化构建和部署:需要更方便地进行整体构建和部署,尤其对于有相互依赖关系的子项目。

  6. 敏捷开发和迭代:需要加快开发和迭代周期,避免在多个代码仓库之间切换和同步。

Monorepo有哪些缺点

  1. 性能问题:当仓库的代码规模非常的巨大,达到GB/TB的级别,会增大开发环境的代码git clone、pull成本,以及安装成本,本地硬盘的压力,执行git status也可能需要花费数秒甚至数分钟的时间。

  2. 打包构建需要专门优化,否则会出现打包时间过长。

  3. 权限管理问题:项目粒度的权限管理较为困难,github、gitlab权限目前不支持文件夹级别。

  4. 特定开发工具和框架限制,灵活性差。

未来趋势

期望Nx 或者 Turborepo 这样的库往完整的框架发展,或者包管理器pnpm/npm自身就逐步支持相应的功能,不需要过多的三方依赖。

参考

  1. https://monorepo.tools/#workspace-analysis

  2. https://developer.aliyun.com/article/1067018#slide-6

  3. https://juejin.cn/post/7098609682519949325#heading-9

  4. https://segmentfault.com/a/1190000039157365

  5. https://pnpm.io/workspaces

  6. https://turbo.build/repo/docs

  7. https://lerna.js.org/docs/getting-started

想了解更多转转公司的业务实践,点击关注下方的公众号吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/575194.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

21 VueComponent 事件的处理

前言 这是最近的碰到的那个 和响应式相关的问题 特定的操作之后响应式对象不“响应“了 引起的一系列的文章 主要记录的是 vue 的相关实现机制 呵呵 理解本文需要 vue 的使用基础, js 的使用基础 测试用例 测试用例如下, 一个简单的 按钮事件的触发 问题的调试 调用…

理解 Linux 文件权限

章节目录&#xff1a; 一、Linux 的安全性1.1 /etc/passwd 文件1.2 /etc/shadow 文件1.3 添加新用户1.4 删除用户1.5 修改用户 二、使用 Linux 组2.1 /etc/group 文件2.2 创建新组2.3 修改组 三、理解文件权限3.1 使用文件权限符号3.2 默认文件权限 四、更改安全设置4.1 修改权…

chatgpt赋能python:Python如何捕捉窗口?——一位有10年Python编程经验的工程师谈Windows操作系统编程

Python 如何捕捉窗口&#xff1f;——一位有10年Python编程经验的工程师谈Windows操作系统编程 自从计算机出现以来&#xff0c;人们就开始与操作系统打交道。而对于Windows系统而言&#xff0c;捕捉窗口通常需要在应用程序级别完成。但是&#xff0c;使用Python与Windows编程…

新手须知的pr入门知识,小红书媒介话术分享

我们都知道&#xff0c;这是一个内容为王的时代。在众多的平台上&#xff0c;都存着无数优秀的内容产出者&#xff0c;也就是达人。今天对新手须知的pr入门知识&#xff0c;小红书媒介话术分享。 一、什么是pr PR即Public Relations的简称&#xff0c;翻译过来就是公关的意思 。…

惠普HP4294A(110M) 安捷伦agilent 4294a精密阻抗分析仪

HP/Agilent 4294A 精密阻抗分析仪是一种集成解决方案&#xff0c;可对元件和电路进行有效的阻抗测量和分析。HP/Agilent 4294A 覆盖更宽的测试频率范围&#xff08;40 Hz 至 110 MHz&#xff09;&#xff0c;基本阻抗精度为 /-0.08%。出色的高 Q/低 D 精度可实现低损耗组件的分…

恭喜,拿到华为OD offer了,并分享刷题经验

目录 一、先介绍一下华为OD是个什么鬼&#xff1f;1、华为OD背景2、华为OD现状3、华为OD趋势4、华为OD介绍&#xff08;1&#xff09;人力外包&#xff08;2&#xff09;员工关系&#xff08;3&#xff09;工作关系&#xff08;4&#xff09;薪酬福利&#xff08;5&#xff09;…

Window MinGW 编译 OpenCV 人快疯了看这里!

目录 一、使用官方编译好的 二、使用MinGW编译器自行进行编译 三、编译好的OpenCV库 OpenCV3.4.5 OpenCV 4.5.4 一、使用官方编译好的 【Qt】opencv源码&官方编译好的opencv在windows下使用的区别_外来务工人员徐某的博客-CSDN博客 官方替我们编译好了&#xff0c;可以直…

一篇文章带你了解Netty

Netty 传统的IO模型的web容器&#xff0c;比如老版本的Tomcat&#xff0c;为了增加系统的吞吐量&#xff0c;需要不断增加系统核心线程数量&#xff0c;或者通过水平扩展服务器数量&#xff0c;来增加系统处理请求的能力。有了NIO之后&#xff0c;一个线程即可处理多个连接事件…

DNSPod十问崔久强:证书有效期缩短,CA机构要凉透?

本期嘉宾 崔久强 上海CA中心总经理 崔久强&#xff0c;上海市数字证书认证中心有限公司总经理、上海市静安区政协委员、第一届上海市智慧城市建设领军先锋、一带一路信息产业发展联盟数字签名专委会主任委员、中国电子认证产业联盟专委会委员、中国密码学会电子认证专委会理事…

【P35】JMeter 包含控制器(Include Controller)

文章目录 一、包含控制器&#xff08;Include Controller&#xff09;参数说明二、准备工作三、测试计划设计3.1、保存测试片段3.2、使用测试片段 一、包含控制器&#xff08;Include Controller&#xff09;参数说明 可以将测试计划的某一部分提取为公用逻辑&#xff0c;这样…

Goby 漏洞更新 |中保無限Modem Configuration Interface 默认口令漏洞

漏洞名称&#xff1a;中保無限Modem Configuration Interface 默认口令漏洞 English Name&#xff1a;Gemtek Modem Configuration Interface Default password vulnerability CVSS core: 5.0 影响资产数&#xff1a;4521 漏洞描述&#xff1a; Modem Configuration Inter…

chatgpt赋能python:Python操作网页的SEO

Python操作网页的SEO 在当今的数字时代&#xff0c;许多企业专注于提高其网站的排名。在这种竞争激烈的环境中&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;是必不可少的。虽然有许多方法可以提高网站的排名&#xff0c;但其中一个最重要的是使用Python来操作网页。 …

Git进阶·GitFlow·壹

文章目录 1 Git进阶——GitFlow工作流程1.1 master与develop分支1.1.1 master1.1.2 develop 1.2 feature分支1.3 Release分支1.4 hotfix分支1.5 GitFlow示例1.5.1 在master上新建dev分支1.5.2 基于dev创建feature分支1.5.3 feature分支上开发业务代码1.5.4 将feature合并到dev1…

Linux的进程信号(上)

文章目录 1. 信号入门2. 技术应用角度的信号3. 信号概念4. 信号处理常见方式5. 产生信号5.1 通过终端按键产生信号5.2 调用系统函数向进程发信号5.3 由软件条件产生信号5.4 硬件异常产生信号 6. Core Dump 1. 信号入门 在生活中&#xff0c;比如红绿灯&#xff0c;铃声这些&am…

chatgpt赋能python:Python指定行:如何快速定位和修改代码?

Python指定行&#xff1a;如何快速定位和修改代码&#xff1f; 在日常Python编程中&#xff0c;我们经常需要在众多行的代码中找到一个特定行&#xff0c;进行修改或者执行操作。如果依靠肉眼逐行检查&#xff0c;不仅费时费力&#xff0c;而且容易漏看或者出错。那么有没有一…

chatgpt赋能Python-python_或与非

介绍 随着互联网的不断发展&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;已经成为了数百万网站主必不可少的一项工作。而Python作为一门高效&#xff0c;灵活和易于阅读的编程语言&#xff0c;不仅可以加快SEO的工作进程&#xff0c;同时也可以提高工作效率。本文将重…

Linux读写锁逻辑解析

一、Linux为何会引入读写锁&#xff1f; 除了mutex&#xff0c;在linux内核中&#xff0c;还有一个经常用到的睡眠锁就是rw semaphore&#xff08;后文简称为rwsem&#xff09;&#xff0c;它到底和mutex有什么不同呢&#xff1f;为何会有rw semaphore&#xff1f;无他&#xf…

在Flask中构建API接口

重定向行为 斜杠 以下两个路由的不同之处在于是否使用尾部的斜杠。 第一个路由的URL尾部有一个斜杠&#xff0c;看起来就像一个文件夹&#xff0c;访问一个没有斜杠结尾的URL时&#xff0c;Flask会自动进行重定向&#xff0c;在结尾加上一个斜杠。 第二个路由的URL没有尾部…

CVPR 2023 | 风格迁移论文3篇简读,视觉AIGC系列

CAP-VSTNet: Content Affinity Preserved Versatile Style Transfer 内容相似度损失&#xff08;包括特征和像素相似度&#xff09;是逼真和视频风格迁移中出现伪影的主要问题。本文提出了一个名为CAP-VSTNet的新框架&#xff0c;包括一个新的可逆残差网络&#xff08;reversib…

微信小程序一键登录功能,使用uni-app和springboot(JWT鉴权)

目录 概述 微信登录接口说明 关于获取微信用户的信息 前端代码&#xff08;uni-app&#xff09; 后端代码&#xff08;SpringBoot&#xff09; 配置文件&#xff1a;application.yml 配置文件&#xff1a;Pom.xml 类&#xff1a;WeChatModel 类&#xff1a;WeChatSe…