ByteNoteByteNote

字节笔记本

2026年7月20日

Monorepo 最佳实践:从前端到全栈的仓库管理方案

API中转
¥120

Monorepo 最佳实践:从前端到全栈的仓库管理方案

Monorepo(单仓库多项目)把多个相关项目放在同一个 Git 仓库中管理。本文介绍 Monorepo 的适用场景、工具选型,以及前端和全栈项目的目录结构设计。

什么时候该用 Monorepo

适合 Monorepo 的典型场景:

  • 多端前端:小程序 + H5 + 管理后台共享组件和工具函数
  • 前后端一体:前端项目 + 后端 API 共享类型定义和配置
  • 微服务集群:多个 Go/Node 服务共享公共库
  • 开源项目:核心库 + 示例 + 文档在同一仓库

不适合的场景:

  • 各项目之间没有代码共享
  • 团队成员只负责各自项目,没有协作需求
  • 构建时间已经成为瓶颈

前端 Monorepo:pnpm + Turborepo

目录结构

text
my-monorepo/
├── pnpm-workspace.yaml     # workspace 配置
├── turbo.json               # Turborepo 构建配置
├── package.json             # 根 package.json
├── packages/
│   ├── shared/              # 共享包
│   │   ├── src/
│   │   │   ├── request.ts   # 封装的请求工具
│   │   │   ├── storage.ts   # 本地存储封装
│   │   │   └── types.ts     # 共享类型定义
│   │   └── package.json
│   ├── miniapp/             # 小程序项目
│   │   ├── src/
│   │   └── package.json
│   └── admin/               # 管理后台
│       ├── src/
│       └── package.json
└── tsconfig.json

pnpm workspace 配置

yaml
# pnpm-workspace.yaml
packages:
  - 'packages/*'

根 package.json

json
{
  "name": "my-monorepo",
  "private": true,
  "scripts": {
    "dev": "turbo run dev",
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test"
  },
  "devDependencies": {
    "turbo": "^1.10.0",
    "typescript": "^5.3.0"
  }
}

turbo.json 构建配置

json
{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {},
    "test": {
      "dependsOn": ["build"]
    }
  }
}

dependsOn: ["^build"] 表示当前包的 build 依赖所有上游包的 build 先完成。Turborepo 会根据依赖图自动确定执行顺序,并缓存构建结果。

子项目引用共享包

json
// packages/miniapp/package.json
{
  "dependencies": {
    "@proj/shared": "workspace:*"
  }
}

workspace:* 表示使用 workspace 内的最新版本,pnpm 会自动创建软链接。

共享工具示例

typescript
// packages/shared/src/request.ts
interface ApiResponse<T> {
  code: number
  data: T
  message: string
}

export async function request<T>(url: string, options?: RequestInit): Promise<T> {
  const response = await fetch(url, {
    headers: { 'Content-Type': 'application/json', ...options?.headers },
    ...options,
  })
  const result: ApiResponse<T> = await response.json()
  if (result.code !== 0) throw new Error(result.message)
  return result.data
}

// packages/shared/src/storage.ts
const isPlatform = () => {
  if (typeof wx !== 'undefined') return 'wx'
  if (typeof window !== 'undefined') return 'web'
  return 'node'
}

export const storage = {
  get(key: string) {
    const platform = isPlatform()
    if (platform === 'wx') return wx.getStorageSync(key)
    return localStorage.getItem(key)
  },
  set(key: string, value: string) {
    const platform = isPlatform()
    if (platform === 'wx') return wx.setStorageSync(key, value)
    return localStorage.setItem(key, value)
  }
}

通过平台判断,同一套代码可以在小程序和 Web 中复用。

全栈 Monorepo:前端 + Go 后端

当项目同时包含前端和后端时,可以用 pnpm 管理前端,Go modules 管理后端。

目录结构

text
my-project/
├── packages/
│   ├── shared/          # 前端共享包
│   ├── miniapp/         # 小程序
│   └── admin/           # 管理后台(Vue3)
├── server/              # Go 后端
│   ├── cmd/
│   │   └── main.go      # 入口
│   ├── internal/        # 内部包(不对外暴露)
│   ├── pkg/             # 可复用的公共包
│   └── go.mod
├── pnpm-workspace.yaml
├── turbo.json
└── docker-compose.yml   # 本地开发环境(MySQL 等)

pnpm-workspace.yaml 排除 Go 后端目录:

yaml
packages:
  - 'packages/*'
  - '!packages/server'

docker-compose.yml

yaml
version: '3'
services:
  mysql:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: myapp
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql

volumes:
  mysql_data:

版本管理:Changesets

当 monorepo 中的包需要独立发版时,用 Changesets 管理版本号和 CHANGELOG。

bash
# 安装
pnpm add -Dw @changesets/cli

# 初始化
npx changeset init

# 记录变更
npx changeset
# 交互式选择:哪些包有变更、语义化版本级别(patch/minor/major)

# 版本升级
npx changeset version

# 发布
npx changeset publish

Monorepo vs 多仓库对比

维度Monorepo多仓库(Multirepo)
代码共享天然方便,直接 import需要发包或 Git Submodule
版本管理Changesets 自动关联各仓库独立管理
CI/CD需要增量构建(Turborepo 缓存)简单直接
权限控制全仓库统一权限可以按仓库分别授权
代码审查可以跨项目审查独立审查
初期搭建需要配置工具链零配置
仓库体积较大各仓库独立

常用工具对比

工具语言生态特点
TurborepoJS/TS增量构建、远程缓存、配置简单
NxJS/TS功能最全、插件丰富、学习曲线陡
LernaJS/TS老牌工具、社区大、配置灵活
pnpm workspaceJS/TS包管理器原生支持,通常与 Turbo/Nx 搭配
Go workspaceGoGo 1.18+ 原生多模块支持
Bazel多语言Google 出品、功能强大、配置复杂

对于中小型项目,pnpm + Turborepo 是最实用的组合。大型团队或企业级项目可以考虑 Nx。

总结

Monorepo 的核心价值在于代码共享和统一管理。pnpm workspace 解决包管理问题,Turborepo 解决构建效率问题,Changesets 解决版本管理问题。对于前后端一体的项目,pnpm 管前端、Go modules 管后端、docker-compose 管基础设施,可以组成一套完整的开发工作流。

分享: