monorepo架构设计方案

一、理论知识

1. 定义

英文为 Monorepo (Monolithic Repository),译为单一代码仓库,是一种项目管理策略:

  1. 核心特征:多个相关项目/包存储在同一个代码仓库中
  2. 本质:工程化架构方案,解决多项目管理问题
  3. 对比:传统 Multirepo(多仓库) vs Monorepo(单仓库)
2. 优势
  1. 统一项目结构:混合式管理,所有工程形成有机整体
  2. 技术栈统一:团队基建、业务项目、子项目保持一致性,提高代码的复用性和团队协作的便捷性
  3. 高效共享机制:规范化、自动化、流程化项目间共享
  4. 依赖管理:依赖提升(Dependency hoisting),版本一致性保证,避免重复安装
  5. 统一开发体验:单点代码提交,全局代码搜索,统一CI/CD流程
3. 解决了什么问题(传统架构痛点)
问题维度传统架构(Multirepo)Monorepo解决方案
项目结构独立仓库,碎片化管理统一仓库,结构化组织
技术栈各项目独立,升级困难统一技术栈,平滑升级
代码复用复制粘贴或私有包,效率低下直接引用,实时同步
依赖管理版本冲突,重复安装,磁盘膨胀依赖提升,单实例安装
协作效率跨仓库修改困难,MR流程复杂单仓库修改,原子提交
工具链各项目独立配置,维护成本高统一配置,集中管理

二、实现一个简单的monorepo项目

1. 项目目录结构
- monorepo(项目名字)
	|- apps(子项目目录)
		|- project1(子项目1目录)
			|- package.json(配置文件)(见下方代码)
			|- index.html(入口文件)
			|- src(源码目录)
				|- index.js
		|- project2(子项目2目录)
	|- packages(公共工具包/组件库目录)
		|- ui(UI组件库目录)
		|- tools(工具组件库目录)
			|- package.json(配置文件)(见下方代码)
			|- index.js(入口文件)
			|- src(源码目录)
				|- date.js
		|- cli(脚手架工具目录)
	|- package.json(根目录配置文件)(见下方代码)
	|- pnpm-workspace.yaml(pnpm配置文件)(见下方代码)

根目录package.json

{
    "name": "monorepo", // 项目的名字,建议使用 kebab-case(短横线分隔)【推荐命名:<组织名>-<项目名>】
    "version": "1.0.0", // 如果根包不发布,这个字段也不是必须的
    "private": true, // 表示这个包是私有的,不会被发布到npm(或其他包管理器)上。在monorepo的根目录设置`"private": true`是一个最佳实践,因为根目录通常不是要发布的包,而是包含多个子包的工作区。
    "scripts": { // 一些npm/pnpm脚本
        "dev": "vite"
    },
    "devDependencies": {
        "vite": "^7.1.1"
    }
}
# pnpm-workspace.yaml
packages:
  - 'packages/*'  # 子包存放路径
  - 'apps/*'      # 应用存放路径

在子包的package.json中设置入口main,这里以monorepo/packages/tools举例

# package.json
{
    "name": "@monorepo-demo/tools",
    "private": true,
    "main": "index.js", #入口文件
    "version": "1.0.0"
}

date.js

function getNow(){
    return new Date();
}

export {
    getNow,
}

apps/project1/package.json

{
    "name": "@monorepo-demo/project1",
    "private": true,
    "version": "1.0.0",
    "scripts": {
        "dev": "vite"
    },
}
2. 安装pnpm

通过npm全局安装
- 确保已安装Node.js(版本≥18.12)。
- 执行命令:npm install -g pnpm
- 验证安装:pnpm --version‌‌

为什么使用pnpm?

特性说明
软链接机制node_modules 中通过符号链接直接指向工作区包,创建虚拟存储,避免文件复制,节省磁盘空间。
依赖缓存下载过的依赖会存储在全局存储中,其他项目再次安装时直接硬链接,极快。
原生 Workspace内置 workspace: 协议,轻松链接本地包。
磁盘空间优化相同依赖只存储一份,大幅减少磁盘占用。
依赖隔离避免幽灵依赖(未声明却能引用)和非法访问(隔离 node_modules 结构)。

总结:pnpm 通过中心化存储和软链接,完美解决 Monorepo 中依赖复用和隔离问题。

3. 用pnpm在根目录工作区安装vite
pnpm add -w -D vite

然后根目录的node_modules就有了vite
在这里插入图片描述

4. 给子项目安装子包工具

cd进入子项目project1中,执行:

pnpm add @monorepo-demo/tools --workspace

workspace:工作区中
@monorepo-demo/tools:子包的package.json中定义的名字
然后我们子包的package.json就更新为:
在这里插入图片描述
同时node_modules中就出现了我们的工具子包库。

5.在子项目运行

在project1目录下,运行npm run dev(需要如上配置script)可以成功运行:
在这里插入图片描述

6.在根目录运行

在根目录下,运行

pnpm run --F @monorepo-demo/project1 dev
# -- F时filter筛选的意思

成功运行,和上面一样的结果。

三、最佳实践

1. 项目结构设计
monorepo/
├── apps/                  # 应用项目
│   ├── web-app/           # 前端应用
│   └── mobile-app/        # 移动端应用
├── packages/              # 共享包
│   ├── core/              # 核心工具库
│   ├── ui/                # UI组件库
│   └── configs/           # 共享配置(ESLint/Prettier等)
├── package.json           # 根配置
├── pnpm-workspace.yaml    # 工作区配置
└── turbo.json             # 任务编排配置(可选)
2. 关键配置文件详解
packages:
  - 'apps/*'               # 应用项目
  - 'packages/*'           # 共享包
  - 'internal/*'           # 内部工具(可选)

根目录package.json

{
  "name": "company-monorepo",  // 推荐命名:<组织名>-monorepo
  "version": "1.0.0",
  "private": true,            // 防止意外发布
  "scripts": {
    "dev": "turbo run dev",   // 使用任务编排工具
    "build": "turbo run build"
  },
  "devDependencies": {
    "turbo": "^2.0.0",        // 推荐添加任务编排工具
    "typescript": "^5.0.0"
  },
  "packageManager": "pnpm@8.15.0"  // 锁定包管理器版本
}
3. 工作流命令详解(PNPM 核心命令)
pnpm add -wD <pkg>	# 安装到根目录,共享开发依赖(Vite/ESLint)
pnpm --filter <package> add <pkg>	# 指定包安装,给特定子包添加依赖
pnpm add workspace:<package>	# 链接本地包,项目引用共享包
pnpm run --parallel <script>	#并行执行,同时启动多个应用
pnpm exec -- <command>	# 执行命令,运行全局工具
4. 高级工作流
  1. 全局启动所有应用
# 使用 TurboRepo 并行执行
pnpm turbo run dev

# 纯 PNPM 方式
pnpm run --parallel --recursive dev
  1. 过滤特定项目
# 启动 web-app 项目
pnpm --filter @company/web-app dev

# 启动所有以 "admin-" 开头的项目
pnpm --filter "admin-*" dev
5.补充:现代 Monorepo 工具链
  1. 任务编排:
    Turborepo:增量构建,云缓存
    Nx:智能任务调度,依赖图可视化

  2. 变更管理:
    Changesets:自动化版本管理和 CHANGELOG
    Lerna:传统 Monorepo 发布工具

  3. 开发环境:
    Vite:极速开发服务器
    TS-Path:跨项目 TypeScript 引用

  4. 代码质量:
    统一 ESLint/Prettier 配置
    共享 Vitest/Jest 测试配置

在这里插入图片描述

四、常见问题解决方案

1. 循环依赖问题:
  • 使用 pnpm ls --depth 100 检测依赖环
  • 架构设计:提取公共模块到核心包
2. 幽灵依赖问题:

启用 pnpm 严格模式:

# .npmrc
strict-peer-dependencies=true
auto-install-peers=false
3.TypeScript 跨项目引用:
// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@company/*": ["packages/*/src"]
    }
  }
}
4. Docker 多阶段构建:
# 第一阶段:安装依赖
FROM node:18 AS installer
WORKDIR /app
COPY . .
RUN pnpm install --frozen-lockfile

# 第二阶段:构建特定应用
FROM installer AS builder
RUN pnpm turbo run build --filter=web-app...

# 第三阶段:生产镜像
FROM nginx:alpine
COPY --from=builder /app/apps/web-app/dist /usr/share/nginx/html
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值