侧边栏壁纸
  • 累计撰写 47 篇文章
  • 累计创建 2 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

工程化:Monorepo单一仓库

Monorepo 是什么?

Monorepo 就是将多个相关项目的代码,放在同一个代码仓库中进行管理。通过牺牲一定的仓库隔离性,换来了极高的开发协同效率和一致性。

优缺点
  1. 优点

    代码复用性高:公共组件、工具函数、配置可以轻松在项目间共享。
    简化依赖管理:特别是处理内部互相依赖的包时,可以避免“依赖地狱”。
    统一的工具链:ESLint, Prettier, 测试框架,构建工具等可以全局统一配置,保证一致性。
    原子更改:修改一个底层库时,可以同时更新所有依赖它的项目,并确保一次提交就能完成,易于回滚和追溯。
    更简单的 CI/CD:理论上可以设置统一的流水线,但需要精心设计以优化构建速度。

  2. 缺点

    仓库体积巨大:随着时间推移,仓库会变得非常庞大,对 Git 操作和 IDE 性能是挑战。
    权限控制复杂:如何确保团队只能访问其负责的模块,需要额外的工具和策略。
    构建和测试优化:需要智能的工具(如 Turborepo, Nx, Lage)来支持增量构建和缓存,避免每次全量构建。
    对工具链要求高:需要搭配专业的 Monorepo 管理工具才能发挥其优势。

常用的 Monorepo 管理工具
  1. 基于 NPM/Yarn/PNPM 的工作区:
    PNPM Workspace:目前非常流行,利用硬链接节省磁盘空间,依赖管理高效。
    Yarn Workspaces:Yarn 内置的 Monorepo 支持。
    NPM Workspaces:NPM v7+ 开始内置。
  2. 高级构建系统:
    Turborepo:Vercel 出品,主打极快的增量构建和智能缓存。
    Nx:功能非常强大,提供代码生成、依赖图可视化、分布式任务执行等。
    Rush:Microsoft 出品,专注于大规模 Monorepo 管理。

如何使用?
  1. 初始化项目
mkdir my-monorepo-demo
cd my-monorepo-demo
echo "packages:
  - 'packages/*'
  - 'apps/*'" > pnpm-workspace.yaml

  1. 创建子包(共享包)
mkdir packages
cd packages
mkdir ui
cd ui
pnpm init
//手动将包名改为 @my-repo/ui
  1. 创建应用
cd ../.. // 回到根目录
mkdir apps
pnpm create next-app@latest apps/web-app --typescript --tailwind --app --no-eslint
  1. 安装 Turborepo(构建系统)
pnpm add -Dw turbo
echo>turbo.json // 创建文件

编辑 turbo.json

{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      // 一个包(包A)的构建任务,依赖于其依赖包(包B)的 `build` 任务先完成
      "dependsOn": ["^build"],
      // 此任务的输出(如 dist 目录)应该被缓存
      "outputs": ["dist/**", ".next/**"]
    },
    "dev": {
      // dev 任务默认不缓存
      "cache": false
    },
    "lint": {
      // lint 任务可以并行执行,无特殊依赖
      "outputs": []
    },
    "test": {
      // test 任务依赖于 `build` 任务
      "dependsOn": ["build"],
      "outputs": []
    }
  }
}

更新根目录的 package.json

{
  "name": "my-monorepo-demo",
  "private": true,
  "packageManager": "pnpm@9.0.0",
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
    "lint": "turbo run lint",
    "test": "turbo run test"
  },
  "devDependencies": {
    "turbo": "latest"
  }
}
  1. 建立包之间的依赖关系

编辑 apps/web-app/package.json

("workspace:*"是 PNPM Workspace 的协议,表示直接链接工作区内的本地包,而不是从 npm 仓库下载。)

{
  "dependencies": {
    "@my-repo/ui-button": "workspace:*",
    "@my-repo/utils": "workspace:*"
  }
}
  1. 统一安装所有依赖并运行
# 在项目根目录执行,这将安装所有 packages 和 apps 下的依赖
pnpm install
# 运行开发命令,Turborepo 会并行启动所有包的 `dev` 脚本(如果定义了的话)
pnpm dev
# 或者,运行构建命令。Turborepo 会智能地分析依赖图:
# 1. 先构建没有任何内部依赖的包(如 utils)。
# 2. 再构建依赖了 utils 的包(如 ui)。
# 3. 最后构建应用(web-app),因为它依赖了前两个包。
# 并且会缓存结果,下次构建时跳过未变更的部分。
pnpm build
  1. 区别

    Monorepo 为了系统性解决代码共享和项目管理

    npm link 是临时的开发调试工具。

  2. 何时使用哪个?

    a. 使用 npm link 的情况:
    快速测试一个第三方库的本地修改
    在独立仓库之间进行临时代码调试
    你没有权限或不需要重构项目结构
    一次性、短期的测试需求
    b. 使用 Monorepo 的情况:
    长期维护多个相互依赖的项目
    需要跨项目统一代码规范、工具链
    团队协作,需要原子提交和统一的 CI/CD
    项目间共享大量代码和配置
    有长期规划的项目群

项目权限管理

因为所有代码都在同一个仓库里,如何确保团队成员只能访问和修改他们负责的部分,是 Monorepo 落地企业级场景必须解决的问题

  1. 解决方案 A:基于路径的代码所有权

GitHub Code Owners 示例:

# .github/CODEOWNERS
# 前端团队拥有前端代码
/apps/web-app/*     @org/frontend-team
/apps/admin/*       @org/frontend-team

# 后端团队拥有后端代码
/apps/api/*         @org/backend-team
/packages/api-sdk/* @org/backend-team

# 基础架构团队拥有共享配置
/packages/config/*  @org/platform-team
/tooling/*         @org/platform-team

# 核心包需要多个团队审批
/packages/ui/*      @org/frontend-team @org/design-system-team

创建 Pull Request
自动要求 @org/frontend-team 审批

  1. 解决方案 B:分支保护规则
# GitHub 分支保护规则示例
# 保护 main 分支:
rules:
  - branch: "main"
    # 必须通过 CI 检查
    checks: ["ci/build", "ci/test"]
    # 必须经过 review
    reviews: 1
    # 不同路径需要不同团队的 review
    path_rules:
      - paths: ["apps/frontend/**"]
        required_approving_review_count: 1
        required_reviewers: ["frontend-team"]
      - paths: ["apps/backend/**"]
        required_approving_review_count: 1
        required_reviewers: ["backend-team"]
      - paths: ["packages/shared/**"]
        required_approving_review_count: 2
        required_reviewers: ["frontend-team", "backend-team"]

0

评论区