单仓库管理 monorepo-management

本技能提供单仓库架构的管理方法,包括使用 Lerna、Turborepo 和 Nx 等工具来配置工作区、依赖版本控制和跨软件包测试,适用于多软件包项目和微服务架构。

架构设计 0 次安装 0 次浏览 更新于 3/4/2026

单仓库管理

概述

建立可扩展的单仓库结构,支持多个相互依赖的软件包,同时保持构建效率、依赖管理和部署协调。

何时使用

  • 多软件包项目
  • 跨服务共享库
  • 微服务架构
  • 基于插件的系统
  • 多应用平台(Web + 移动)
  • 工作区依赖管理
  • 团队规模化开发

实施示例

1. Npm 工作区配置

{
  "name": "monorepo-root",
  "version": "1.0.0",
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*"
  ],
  "devDependencies": {
    "lerna": "^7.0.0",
    "turbo": "^1.10.0"
  },
  "scripts": {
    "lint": "npm run lint -r",
    "test": "npm run test -r",
    "build": "npm run build -r",
    "clean": "npm run clean -r"
  }
}

2. Lerna 配置

{
  "name": "monorepo-with-lerna",
  "version": "1.0.0",
  "private": true,
  "packages": [
    "packages/*",
    "apps/*"
  ],
  "command": {
    "bootstrap": {
      "hoist": true,
      "ignore": "@myorg/infra"
    },
    "publish": {
      "conventionalCommits": true,
      "createRelease": "github",
      "message": "chore(release): publish"
    }
  }
}

3. Turborepo 配置

{
  "turbo": {
    "globalDependencies": ["tsconfig.json"],
    "pipeline": {
      "build": {
        "dependsOn": ["^build"],
        "outputs": ["dist/**", ".next/**"],
        "cache": true
      },
      "test": {
        "dependsOn": ["^build"],
        "cache": true,
        "outputs": ["coverage/**"]
      },
      "lint": {
        "outputs": []
      },
      "dev": {
        "cache": false,
        "persistent": true
      }
    }
  }
}

4. Nx 工作区配置

{
  "version": 2,
  "projectNameAndRootFormat": "as-provided",
  "plugins": [
    "@nx/next/plugin",
    "@nx/react/plugin",
    "@nx/node/plugin"
  ],
  "targetDefaults": {
    "build": {
      "cache": true,
      "inputs": [
        "production",
        "^production"
      ]
    },
    "test": {
      "cache": true,
      "inputs": [
        "default",
        "^production"
      ]
    }
  }
}

5. 单仓库目录结构

monorepo/
├── packages/
│   ├── core/
│   │   ├── src/
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── utils/
│   │   ├── src/
│   │   ├── package.json
│   │   └── tsconfig.json
│   └── shared/
│       ├── src/
│       ├── package.json
│       └── tsconfig.json
├── apps/
│   ├── web/
│   │   ├── pages/
│   │   ├── package.json
│   │   └── next.config.js
│   ├── api/
│   │   ├── src/
│   │   ├── package.json
│   │   └── tsconfig.json
│   └── mobile/
│       ├── src/
│       ├── package.json
│       └── app.json
├── tools/
│   ├── scripts/
│   └── generators/
├── lerna.json
├── turbo.json
├── nx.json
├── package.json
├── tsconfig.json
└── .github/workflows/

6. 工作区依赖

{
  "name": "@myorg/web-app",
  "version": "1.0.0",
  "dependencies": {
    "@myorg/core": "workspace:*",
    "@myorg/shared-ui": "workspace:^",
    "@myorg/utils": "workspace:~"
  },
  "devDependencies": {
    "@myorg/test-utils": "workspace:*"
  }
}

7. Lerna 命令

# 引导软件包并安装依赖项
lerna bootstrap

# 安装依赖项并提升公共项
lerna bootstrap --hoist

# 创建新版本
lerna version --conventional-commits

# 发布所有更改的软件包
lerna publish from-git

# 在所有软件包中运行命令
lerna exec -- npm run build

# 并行运行命令
lerna exec --parallel -- npm run test

# 列出所有软件包
lerna list

# 显示依赖图
lerna graph

# 在特定软件包中运行脚本
lerna run build --scope="@myorg/core" --include-dependents

8. Turborepo 命令

# 按依赖顺序构建所有软件包
turbo run build

# 使用特定过滤器构建
turbo run build --filter=web --filter=api

# 排除某些软件包构建
turbo run build --filter='!./apps/mobile'

# 带缓存运行测试
turbo run test --cache-dir=.turbo

# 开发模式(无缓存)
turbo run dev --parallel

# 显示执行图
turbo run build --graph

# 分析构建时间
turbo run build --profile=profile.json

9. CI/CD 单仓库

# .github/workflows/monorepo-ci.yml
name: 单仓库 CI

on: [push, pull_request]

jobs:
  affected:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'

      - name: 安装依赖项
        run: npm ci

      - name: 获取更改的软件包
        id: changed
        run: |
          npx lerna changed --json > changed.json
          echo "packages=$(cat changed.json | jq -r '.[].name')" >> $GITHUB_OUTPUT

      - name: 构建更改的软件包
        run: npx turbo run build --filter='${{ steps.changed.outputs.packages }}'

      - name: 测试更改的软件包
        run: npx turbo run test --filter='${{ steps.changed.outputs.packages }}'

      - name: 检查更改的软件包
        run: npx turbo run lint --filter='${{ steps.changed.outputs.packages }}'

10. 跨软件包版本管理

#!/bin/bash
# sync-versions.sh

# 使用 lerna 保持版本同步
lerna version --exact --force-publish

# 或手动同步 package.json 版本
MONOREPO_VERSION=$(jq -r '.version' package.json)

for package in packages/*/package.json; do
    jq --arg version "$MONOREPO_VERSION" '.version = $version' "$package" > "$package.tmp"
    mv "$package.tmp" "$package"
done

echo "✅ 所有软件包同步到版本 $MONOREPO_VERSION"

最佳实践

✅ 执行

  • 使用工作区协议进行依赖
  • 实施共享 tsconfig 以保持一致性
  • 在 CI/CD 中缓存构建输出
  • 在 CI 中过滤软件包以避免不必要的构建
  • 提升公共依赖项
  • 记录工作区结构
  • 使用一致的版本控制策略
  • 在工作区中实施预提交钩子
  • 测试跨软件包依赖
  • 在适当时独立版本控制软件包

❌ 不要

  • 创建循环依赖
  • 使用工作区软件包的硬编码版本
  • 仅更改一个软件包时构建所有软件包
  • 忘记更新锁文件
  • 忽略工作区边界
  • 创建紧密耦合的软件包
  • 跳过依赖管理
  • 每个软件包使用不同的工具

工作区依赖解析

# workspace:* - 在工作区中使用确切版本
"@myorg/core": "workspace:*"

# workspace:^ - 使用兼容版本
"@myorg/shared": "workspace:^"

# workspace:~ - 使用补丁兼容版本
"@myorg/utils": "workspace:~"

资源