Monorepo 工具大横评:Nx、Turborepo、Lerna、Rush 与 Moon,谁才是你的最佳选择?

434 阅读12分钟

1.什么是 Monorepo?为什么我们需要认真管理它?

Monorepo(单仓库多项目) 是一种将多个应用、库、服务或工具统一放在一个代码仓库中进行管理的开发模式。与传统的 Multi-repo(每个项目独立仓库)不同,Monorepo 允许团队在同一个代码库中协同开发前端应用、共享组件库、后端微服务甚至 CLI 工具。

这种模式在 Google、Meta、Microsoft 等大型科技公司早已广泛应用,近年来也逐渐被中小型团队采纳——因为它能显著降低协作成本、提升代码复用率、简化依赖管理和统一工程规范

然而,Monorepo 的优势背后也隐藏着复杂性:

  • 如何避免每次提交都触发全量构建和测试?
  • 当 utils 库改动时,哪些应用会受到影响?
  • 如何高效并行执行任务,并在 CI 中复用历史构建结果?
  • 新成员如何快速创建符合规范的新项目?

这些问题如果靠脚本或人工维护,很快会陷入混乱。因此,我们需要一套专业的 Monorepo 管理工具——它不仅要支持增量构建、依赖分析、任务缓存,还要提供良好的开发者体验和对主流技术栈(如 React、TypeScript、Node.js)的深度集成。

✅ 本次调研的核心目标:评估当前主流 Monorepo 方案(Nx、Turborepo、Moon 等),判断是否有比 Nx 更适合我司场景的替代方案,或确认 Nx 是否仍是综合最优解。

2. 各个工具的功能鉴赏

2.1 Nx(当前参考基准)

  • 依赖图分析nx graph 可视化项目依赖。
  • 智能缓存:基于源码哈希判断是否需重新构建,支持 Nx Cloud 远程缓存(付费)。
  • 插件生态:官方支持 React、Vue、Angular、NestJS、Next.js 等;社区插件丰富。
  • 代码生成:通过 nx g @nx/react:app my-app 快速创建标准化项目。
  • 任务管道:定义 targetDependencies 实现任务依赖链。

2.2 Turborepo(Vercel 出品)

  • 极简配置:通过 turbo.json 定义 pipeline,学习成本低。
  • 远程缓存免费:集成 Vercel Remote Caching,开源项目可免费使用。
  • 无内置依赖图:需借助第三方工具(如 madge)分析依赖。
  • 专注前端生态:对 Next.js / React 优化最好,其他技术栈支持较弱。

2.3 Lerna(传统方案)

  • 包版本管理强项lerna version + lerna publish 适合 npm 包发布流程。
  • 缺乏增量构建:默认全量执行脚本,需配合 -since 手动过滤。
  • 已转向轻量模式:新版本移除内置 hoisting,推荐搭配 pnpm/yarn workspaces 使用。

2.4 Rush(微软出品)

  • 企业级设计:强调确定性安装、变更日志管理、批量命令执行。
  • 强 TypeScript 支持:自动链接类型定义,适合大型 TS 项目。
  • 配置复杂:需编写 rush.jsoncommon/config/rush/* 等多文件。
  • 依赖图支持rush graph 可生成依赖关系图。

2.5 Moon(新兴高性能方案)

  • 极速执行引擎:基于 Rust 编写,启动和任务调度速度显著优于 JS/TS 工具。
  • 声明式配置:通过单一 moon.yml 文件定义项目结构与任务流水线,简洁清晰。
  • 多语言原生支持:无需插件即可管理 TypeScript、Rust、Python、Go 等项目。
  • 内置缓存与远程执行:支持本地缓存 + 自建远程缓存服务器(无厂商锁定)。
  • 依赖图可视化:提供 moon project graph 命令生成依赖关系图。
  • CI/CD 深度优化moon ci 自动并行化、分片、缓存复用,适合大型流水线。
  • 无代码生成器:当前版本不支持类似 Nx 的 scaffolding 功能,需手动创建项目模板。

💡 Moon 定位为“现代 Monorepo 的高性能替代方案”,强调确定性、可扩展性和开发者效率。


3. 使用的核心流程

工具初始化 Monorepo添加新应用/库构建指定项目增量测试查看依赖图
Nxnpx create-nx-workspace@latestnx g @nx/react:lib uinx build my-app✅ 自动跳过未变更项目nx graph
Turboreponpx create-turbo@latest手动创建目录 + package.jsonturbo run build --filter=my-app✅ 依赖 pipeline 配置❌(需第三方)
Lernalerna init + 配合 pnpm/yarn手动创建包 + lerna create(旧版)lerna run build --scope=my-app⚠️ 需 --since 手动指定
Rushrush initrush add -p my-lib --make-consistentrush build --to my-app✅ 基于变更集rush graph
Moonpnpm create moon手动创建目录 + 在 moon.yml 中注册moon run web:build✅ 自动识别依赖变更moon project graph

💡 注:所有工具均需配合包管理器(如 pnpm workspace 或 yarn workspaces)实现 node_modules 共享。


4. 测试流程 & 结果

4.1 Turborepo 测试流程

步骤 1:初始化项目结构(复用 Nx 创建的目录)

# 在已有 monorepo-test 目录中操作
cd monorepo-test
pnpm add -D turbo

步骤 2:配置 turbo.json

{
  "$schema": "<https://turbo.build/schema.json>",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["^build"],
      "outputs": []
    }
  }
}

⚠️ 注意:Turborepo 不会自动识别项目依赖,必须通过 package.json 中的 dependencies 显式声明(如 web 依赖 @myorg/utils)。

步骤 3:为每个子包添加脚本

  • apps/web/package.json:

    { "scripts": { "build": "vite build" } }
    
  • libs/utils/package.json:

    { "scripts": { "build": "tsc", "test": "jest" } }
    

步骤 4:执行命令测试

功能命令结果
构建 webpnpm turbo run build --filter=web成功,自动构建 utils(因依赖关系)
增量缓存再次运行相同命令输出 cached (local),命中缓存
查看依赖逻辑pnpm turbo run build --dry-run打印任务执行顺序(但无图形化)

Turborepo 缓存命中日志截图 image.png

✅ 优势 vs Nx:

  • 配置极简:仅需 turbo.json + 标准 npm scripts。
  • 远程缓存免费:Vercel 提供开箱即用的 Remote Caching(开源项目免费)。
  • 构建速度更快:任务调度更轻量,尤其适合纯前端栈(React/Vite/Next.js)。

❌ 不足 vs Nx:

  • 无内置依赖图:无法直观查看 web → utils 关系,调试依赖需靠 -dry-run 或第三方工具。
  • 无代码生成器:创建新库需手动配置路径别名、tsconfig、package.json。
  • 弱多技术栈支持:对非 JS/TS 项目(如 Go、Python 微服务)几乎无支持。

4.2 Lerna 测试流程

步骤 1:安装并初始化

pnpm add -D lerna
npx lerna init

⚠️ Lerna 新版本已移除 packages/ 自动 hoisting,需配合 pnpm workspace 使用。

步骤 2:确保包结构正确

  • packages/ 下包含 webutils(需手动移动或创建)
  • 每个包有独立 package.json,且 web 声明依赖 "@myorg/utils": "workspace:*"

步骤 3:执行命令

功能命令结果
构建所有pnpm exec lerna run build全量执行,即使未变更
增量构建pnpm exec lerna run build --since HEAD~1仅构建 git diff 涉及的包
运行测试pnpm exec lerna run test --scope=@myorg/utils可指定范围,但无智能跳过

📌 插图位置:Lerna 全量构建日志 vs 增量构建日志对比

全量构建日志

image.png

增量构建日志

image.png

✅ 优势 vs Nx:

  • npm 包发布流程成熟lerna version + lerna publish 是行业标准。
  • 轻量无侵入:不强制项目结构,适合已有仓库渐进迁移。

❌ 不足 vs Nx:

  • 无增量缓存机制:每次构建都重新执行,CI 耗时长。
  • 无依赖感知-since 仅基于 git,无法理解“间接依赖变更”(如 utils 改了,web 应重测)。
  • 无可视化/代码生成:纯 CLI 工具,开发体验原始。

4.3 Rush 测试流程

步骤 1:初始化

pnpm create @microsoft/rush
rush update  # 安装依赖

⚠️ Rush 强制使用自己的依赖安装机制(不直接兼容 pnpm install)。

步骤 2:添加项目

rush add -p @myorg/utils --make-consistent

实际仍需手动创建 apps/web 和 libs/utils 目录,并配置 rush.json 中的 projects 字段。

步骤 3:配置构建脚本

  • common/config/rush/command-line.json 中定义自定义命令(如 build)。
  • 每个项目需有 package.json 中的对应 script。

步骤 4:执行命令

功能命令结果
构建 web 及依赖rush build --to web成功,自动构建 utils
查看依赖图rush graph生成 .svg 文件,可查看依赖关系
增量测试修改 utils 后运行 rush rebuild仅重构建受影响项目

Rush 生成的依赖图 SVG 截图 image.png

image.png ✅ 优势 vs Nx:

  • 强 TypeScript 集成:自动处理类型链接,避免 paths 配置错误。
  • 企业级确定性:严格控制 node_modules 结构,避免“在我机器上能跑”问题。
  • 变更集管理:支持 rush change 生成 changelog,适合合规团队。

❌ 不足 vs Nx:

  • 配置复杂:需维护 rush.jsoncommand-line.jsonversion-policies.json 等多个配置文件。
  • 学习曲线陡峭:概念多(如 “phased commands”, “variants”),新人上手慢。
  • 生态封闭:插件少,社区活跃度远低于 Nx/Turborepo。

4.4 综合对比表

能力NxTurborepoLernaRush
增量构建✅ 智能依赖感知✅(需正确配置 outputs)⚠️ 仅 git diff✅ 基于变更集
本地缓存
远程缓存✅(Nx Cloud 付费)✅(Vercel 免费)❌(需自建)
依赖图可视化✅ 内置交互式✅(生成 SVG)
代码生成器✅ 丰富插件❌(旧版有)
多技术栈支持✅(Go/Java/Python 等)❌(仅 JS/TS)⚠️(仅 npm 脚本)⚠️(主攻 TS)
配置复杂度
适合场景复杂企业 MonorepoReact/Next.js 快速开发纯 npm 包发布超大型 TS 项目

注意:

  • 若追求 功能完整性 + 长期可维护性Nx 仍是首选
  • 若团队 专注 React/Next.js + 追求极致构建速度Turborepo 值得试点
  • Lerna 仅推荐用于包发布Rush 适合微软级 TS 项目,一般团队慎选。

4.4 Moon 测试流程

步骤 1:初始化 Moon 项目

# 在干净目录中初始化
pnpm create moon
cd monorepo-moon-test

Moon 默认集成 pnpm workspace,并生成基础目录结构。

步骤 2:配置项目结构

手动创建:

  • apps/web/
  • libs/utils/

并在根目录 moon.yml 中注册:

# moon.yml
projects:
  sources:
    - 'apps/*'
    - 'libs/*'

tasks:
  build:
    command: 'vite build'      # apps/web 使用
    inputs: ['src/**']
    outputs: ['dist/**']

  build:                       # libs/utils 使用(覆盖)
    command: 'tsc'
    inputs: ['src/**']
    outputs: ['lib/**']

⚠️ Moon 允许按项目类型覆盖任务定义,或使用 platforms 区分语言。

步骤 3:配置子包 package.json

  • apps/web/package.json:

    {
      "name": "web",
      "dependencies": { "@myorg/utils": "workspace:*" }
    }
    
  • libs/utils/package.json:

    {
      "name": "@myorg/utils"
    }
    

Moon 会自动解析 dependencies 推断项目间依赖。

步骤 4:执行命令测试

功能命令结果
构建 webmoon run web:build成功,自动先构建 utils
增量缓存再次运行相同命令输出 Cache hit,跳过执行
查看依赖图moon project graph生成交互式 HTML 或 PNG 图(取决于配置)

📌 Moon 依赖图

image.png

image.png

✅ 优势 vs Nx:

  • 性能卓越:Rust 引擎在大型仓库中任务调度更快。
  • 缓存自由:远程缓存可自建 HTTP 服务,无 SaaS 绑定
  • 多语言友好:轻松混合 TS + Rust + Python 项目,无需额外插件。
  • CI 开箱即用moon ci 自动优化并行与缓存恢复。

❌ 不足 vs Nx:

  • 无代码生成器:无法一键生成标准化 React 应用或库。
  • 生态较新:社区小,VS Code 插件、调试工具等支持有限。
  • 配置需显式声明:项目必须在 moon.yml 中注册,不如 Nx 自动发现灵活。

4.5 Nx 测试流程

步骤 1:初始化 Nx 项目

# 在干净目录中初始化
npx create-nx-workspace@latest monorepo-nx-test --preset=react-monorepo --appName=web --style=css --nxCloud=false
cd monorepo-nx-test

Nx 默认集成 pnpm(或 yarn/npm,取决于选择),并自动生成 apps/web 和基础配置。
使用 --nxCloud=false 可关闭远程缓存以避免付费提示。

步骤 2:创建共享库并注册项目

Nx 支持通过代码生成器自动创建库,无需手动注册:

# 自动生成 libs/utils 库(TypeScript + Jest)
nx g @nx/react:lib utils --buildable --importPath=@myorg/utils

✅ 此命令会:

  • 创建 libs/utils 目录;
  • 配置 tsconfig 路径别名;
  • project.json 中注册项目;
  • 自动设置构建目标(使用 tscrollup,取决于是否 --buildable)。

步骤 3:配置依赖关系

utils 作为 web 的依赖:

nx g @nx/react:storybook-configuration web  # (可选)仅为演示依赖注入
nx g add-dependency --project=web --dependency=@myorg/utils

或手动编辑 apps/web/package.json(Nx 实际通过 project.json 管理依赖图,但推荐使用 workspace 协议):

{
  "name": "web",
  "dependencies": {
    "@myorg/utils": "workspace:*"
  }
}

🔍 Nx 不依赖 package.json 的 dependencies 推断依赖,而是通过源码中的 import 语句静态分析,因此即使未声明也能识别。但显式声明有助于包管理器(如 pnpm)正确链接。

步骤 4:执行命令测试

功能命令结果
构建 webnx build web成功,自动检测并构建 utils(因 web 中 import 了它)
增量缓存再次运行相同命令输出 With caching enabled... [existing outputs match hash] → skip跳过执行
查看依赖图nx graph启动本地服务,打开交互式依赖图网页,清晰展示 web → utils 关系

✅ Nx 测试总结

  • 自动化程度高:项目创建、路径别名、构建配置均由生成器完成;
  • 依赖感知智能:基于源码分析,而非仅依赖 package.json
  • 缓存机制成熟:本地缓存默认开启,支持远程缓存(Nx Cloud);
  • 可视化强大nx graph 是目前 Monorepo 工具中最友好的依赖图工具之一。

💡 对比 Moon:Nx 在 开发体验(代码生成、自动配置)上更胜一筹;Moon 则在 多语言支持执行性能 上更具前瞻性。


4.6 综合对比表

能力NxTurborepoLernaRushMoon
增量构建✅ 智能依赖感知✅(需正确配置 outputs)⚠️ 仅 git diff✅ 基于变更集✅ 自动依赖感知
本地缓存
远程缓存✅(Nx Cloud 付费)✅(Vercel 免费)❌(需自建)✅(可自建,无厂商锁定)
依赖图可视化✅ 内置交互式✅(SVG)✅(HTML/PNG)
代码生成器✅ 丰富插件
多技术栈支持✅(Go/Java/Python 等)❌(仅 JS/TS)⚠️(仅 npm 脚本)⚠️(主攻 TS)✅(原生多语言)
配置复杂度中低
CI/CD 优化✅(需配置)✅(基础)✅(企业级)✅(moon ci 内置智能)
适合场景复杂企业 MonorepoReact/Next.js 快速开发纯 npm 包发布超大型 TS 项目高性能 + 多语言 Monorepo

5.🎯 最终建议

若追求 功能完整性 + 成熟生态 + 代码生成 → Nx 仍是首选。若团队 专注 React/Next.js + 追求极致构建速度 + 免费远程缓存 → Turborepo 值得试点。若项目包含 Rust/Python/Go 等多语言,且希望统一管理、避免 SaaS 依赖 → Moon 是极具潜力的新选择。Lerna 仅推荐用于纯 npm 包发布场景。Rush 适合超大型 TypeScript 项目(如微软内部),一般团队慎选。

🔮 Moon 代表了下一代 Monorepo 工具的方向:高性能、多语言、去中心化缓存。虽生态尚早,但值得技术前瞻性团队评估。