monorepo
介绍
-在multirepo
中,每个项目都有自己独立的代码仓库、开发流程、发布和部署过程;而在monorepo
中,多个项目则被统一放置在同一个代码仓库中进行管理,共享依赖、工具和代码库。目前,许多著名的开源项目,如Vue3、Babel、React等都采用了monorepo
的方式进行代码管理。
monorepo
优势
- 提高代码复用:支持跨项目共享,公共部分以包的形式共享
- 解决了需要私服发布和管理npm包
- 代码管理更加方便:所有项目都在一个git仓库中
- 唯一依赖源:每个依赖只有一个版本,意味着没有版本冲突,没有依赖地域
缺点
- 代码库规模越来越大,影响存储
- 权限管理,授权后拥有所有子项目的权限
- 学习成本:如果代码库包含了许多紧密耦合的项目,那么新成员的学习曲线会更陡峭
在选择 monorepo
和 multirepo
方案时,需要考虑项目的规模和复杂度
,以及团队的开发流程和协作方式等因素。如果项目规模比较小或者团队比较紧密,可以考虑选择 monorepo 方案;如果项目规模较大或者团队比较分散,可以考虑选择 multirepo 方案。
使用方式
-
yarn+lerna
配套使用,lerna
是专门管理的工具(lerna已宣布停止维护) -
pnpm
天生支持monorepo
模式,(后起之秀)
比较
yarn+lerna
缺点:lerna已经不在更新,等一些问题
优点:可以解决依赖冲突问题,例如不同项目使用的依赖版本不同
pnpm
缺点:
- 依赖版本不同时会造成版本冲突问题,需要统一依赖版本,依赖差异较大的可能不太适合。
优点:
-
安装速度最快(非扁平的包结构,没有yarn/npm的复杂的扁平算法,且只更新变化的文件)
-
节省磁盘空间 (统一安装包到磁盘的某个位置,项目中的node_modules通过hard-link的方式链接到实际的安装地址)原生支持monorepo,无需第三方工具
monorepo项目结构
最简单的结构
monorepo-project
├─ packages # 工作区-项目文件夹
│ ├─ project1 # 项目1
│ │ ├─src
│ │ ├─static
│ │ ├─index.html
│ │ ├─.babelrc # 配置文件
│ │ └─package.json # 项目依赖和脚本配置文件
│ └─ project2 # 项目2
│
├─ package.json # 项目依赖和脚本配置文件
└─ pnpm-workspace.yaml # pnpm的monorepo配置文件
使用yarn和lerna
采用yarn包管理工具及它的workspace功能。加上lerna工具来配套使用
首先需要安装yarn,lerna
npm install -g yarn lerna
初始化项目
lerna init # 固定模式,所有包公用一个版本号
lerna init --independent # 独立模式,每个包独立版本号
配置package.json
{
"workspaces": ["packages/*"] // packages目录下每个子目录作为一个workspace存在
}
创建子项目
cd packages # 进入项目存放的目录
mkdir pkg1 # 创建子项目的文件
cd pkg1 # 进入子项目文件夹
npm init # 初始化项目package.json
一些命令
安装全部依赖
yarn install # 安装所有的项目依赖
安包
yarn add vconsole # 安装到根目录,所有子项目都可以调用
yarn workspace 项目名称 add vconsole # 给指定某一个项目安装依赖
卸载依赖
yarn workspace 项目名称 remove vconsole # 卸载指定项目的指定依赖
安装本地依赖
yarn workspace 项目名称 link # 先将本地依赖链接到全局
yarn workspace 项目名称 add ./packages/pkg3 # 将某本地依赖安装到其他项目
运行
yarn workspace 项目名称 run dev # 执行 dev命令
清理node_modules
lerna clean # 清理每个package下面的node_modules
使用pnpm
pnpm
可以节约磁盘空间并提升安装速度,比如之前安装过的包,会统一存放到一个公共的地方,再次在别的项目安装时候会进行一个软链接,这样就节约了磁盘空间
- 安装速度最快(非扁平的包结构,没有yarn/npm的复杂的扁平算法,且只更新变化的文件)
- 节省磁盘空间 (统一安装包到磁盘的某个位置,项目中的node_modules通过hard-link的方式链接到实际的安装地址)
- 原生支持monorepo,无需第三方工具
pnpm内置了对单一存储库的支持,可以创建一个workspace来将多个项目合并到一个仓库中。
项目结构
monorepo
--utils // 所有子项目都可以通过包形式引入本utils的方法
--workspace
--web-pc // 子项目1
--web-h5 // 子项目2
创建一个monorepo项目
- 初始化仓库
pnpm init
- pacakge.json脚本设置
删除一些无用的参数,并添加一些脚本命令
{
"name": "teacher-apph5-plus",
"version": "1.0.0",
"private": true, // 设置为私有,禁止public
"scripts": {
"bootstrap": "pnpm install",
"preinstall": "npx only-allow pnpm", // 在执行install之前 检查是否用的pnpm工具,不是就不让安装
"clean": "pnpm recursive exec -- rm -rf node_modules && rm -rf node_modules" // 清理npm包
}
}
- 配置pnpm工作区workspaces
根目录创建pnpm-workspace.yaml
文件,定义工作区,例如packages 文件夹
官网介绍:pnpm.io/zh/workspac…
packages:
- 'apps/*'
- 'packages/*'
- 'utils/**'
- 新建.npmrc文件
在根目录下新建.npmrc,增加以下内容
shamefully-hoist=true
strict-peer-dependencies=false
ignore-workspace-root-check=true
shamefully-hoist 是否提升依赖,如果某些工具仅在根目录的node_modules时才有效,可以将shamefully-hoist设置为true来提升那些不在根目录的node_modules,就是将你安装的依赖包的依赖包的依赖包的...都放到同一级别(扁平化)。说白了就是不设置为true有些包就有可能会出问题。
- 创建utils项目和工作区
创建utils文件夹,初始化,然后创建index.js入口文件
cd utils
pnpm init # 初始化package.json
创建完毕后,可以在package.json
中将项目名称改成@xls/utils
防止名称冲突
index.js 入口文件
function sayHi(){
console.log("hello l is linyi")
}
export {
sayHi
}
- 创建packages工作区文件夹
# 在该文件夹内创建子项目 web-pc web-h5
cd packages
npm init vue@3
在子项目中安装本地依赖utils
# 进入子项目文件夹
pnpm add @xls/utils
在main.js中引入使用
// .........
import { sayHi } from '@xls/utils'
sayHi() // 调用
// .........
公共的包不需要打包,因为如下
这里因为不是直接发布到npm的,而是作为依赖放到项目中使用,在你编译项目时会自动跟随项目编译的
全局依赖
在仓库根目录安装,之后即可再所有子项目中使用
pnpm add vue # 在仓库根目录下安装,在所有的字项目中都可以使用
一些命令
// 在仓库根目录下
pnpm install // 安装全部依赖
pnpm recursive exec -- rm -rf node_modules && rm -rf node_modules // 删除所有依赖
启动子项目
pnpm --filter answerdata run dev
pnpm --filter errorbook run dev
安装在项目根目录中的依赖,在所以子项目中可以直接使用
启动全部
pnpm run --filter '*' dev
子项目中安装 本地其它公共包
pnpm --filter vue-demo1 add utils
或者可以进入子项目目录中安装
pnpm add utils
打包子项目
pnpm --filter errorbook run build
最后
yarn+lerna或pnpm
选择yarn+lerna
或pnpm
的monorepo工具应该根据你的具体需求和团队的技术栈进行评估。以下是一些参考因素:
- 团队技术水平:yarn和lerna的学习曲线较陡峭,而PNPM的学习曲线较为平缓。因此,如果团队中有很多新手,pnpm可能是更好的选择。
项目复杂度
:如果你的项目结构非常复杂,需要处理很多依赖关系和版本冲突,那么lerna的功能可能更适合你的需求。性能需求
:如果你关注monorepo工具的性能表现,pnpm可能是更好的选择。pnpm使用了一种名为“虚拟包管理器”的技术,可以显著减少依赖的安装时间和磁盘空间。
新项目推荐使用pnpm