🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

Monorepo 工具大比拼:為什麼我最終選擇了 pnpm + Turborepo?

本文是《從零到一:構建現代化企業級 Monorepo 項目實戰》系列的第二篇。上一篇我們深入分析了 Monorepo 的核心概念,這篇文章將聚焦於工具選型,帶你了解主流 Monorepo 工具的優劣,以及我的選擇理由。

🎯 本文目標

讀完這篇文章,你將了解:

  • 主流 Monorepo 工具的對比分析
  • pnpm workspace 的核心優勢
  • Turborepo 為什麼這麼快
  • 如何根據項目規模選擇合適的工具

📖 Monorepo 工具全景圖

工具分類

Monorepo 工具鏈
├── 包管理器層
│   ├── npm workspaces
│   ├── yarn workspaces  
│   └── pnpm workspace ⭐ (我的選擇)
│
├── 構建編排層
│   ├── Lerna
│   ├── Rush
│   ├── Nx
│   └── Turborepo ⭐ (我的選擇)
│
└── 一體化方案
    ├── Nx (包管理 + 構建)
    └── Rush (包管理 + 構建)

🔍 包管理器對比

npm workspaces vs yarn workspaces vs pnpm workspace

特性 npm yarn pnpm 推薦指數
安裝速度 ⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐ 🏆 pnpm
磁碟空間 ⭐⭐ ⭐⭐ ⭐⭐⭐⭐⭐ 🏆 pnpm
依賴隔離 ⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐⭐ 🏆 pnpm
幽靈依賴 ❌ 有 ❌ 有 ✅ 無 🏆 pnpm
生態成熟度 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ 🏆 npm
學習成本 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ 🏆 npm

pnpm 的殺手級特性

1. 節省磁碟空間(最多節省 75%)

傳統 npm/yarn:

# 每個項目都複製一份依賴
~/projects/
├── project-a/node_modules/lodash/  # 1MB
├── project-b/node_modules/lodash/  # 1MB  
├── project-c/node_modules/lodash/  # 1MB
└── project-d/node_modules/lodash/  # 1MB
# 總共 4MB

pnpm 的硬鏈接:

# 所有項目共享同一份依賴
~/.pnpm-store/
└── [email protected]/     # 1MB(只存一份)

~/projects/
├── project-a/node_modules/lodash/  → 硬鏈接
├── project-b/node_modules/lodash/  → 硬鏈接
├── project-c/node_modules/lodash/  → 硬鏈接
└── project-d/node_modules/lodash/  → 硬鏈接
# 總共只佔用 1MB!

實際效果:

# 我的項目數據
npm:  1.2 GB node_modules
pnpm: 350 MB node_modules

# 節省空間:70.8%!

2. 杜絕幽靈依賴

什麼是幽靈依賴?

// package.json 中沒有聲明 lodash
{
  "dependencies": {
    "some-package": "^1.0.0"  // some-package 依賴了 lodash
  }
}

// 但你居然可以直接用!這就是幽靈依賴
import _ from 'lodash'  // 😱 能用,但不安全!

pnpm 的嚴格模式:

# pnpm 會報錯
Error: Cannot find module 'lodash'
# 必須顯式聲明依賴才能使用 ✅

3. 更快的安裝速度

性能對比(安裝 1000+ 依賴):

npm:  45s  ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
yarn: 32s  ▓▓▓▓▓▓▓▓▓▓▓▓
pnpm: 12s  ▓▓▓▓ ⚡
速度提升:
- 比 npm 快 3.75 倍
- 比 yarn 快 2.67 倍

🚀 構建編排工具對比

Lerna vs Rush vs Nx vs Turborepo

📊 綜合對比

工具 學習曲線 性能 功能豐富度 配置複雜度 社區活躍度 推薦指數
Lerna ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐
Rush ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐ ⭐⭐ ⭐⭐⭐
Nx ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐
Turborepo ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐

1️⃣ Lerna:老牌工具,漸顯疲態

優勢:

# 簡單易用
lerna init
lerna bootstrap
lerna publish

劣勢:

  • ❌ 性能較差(沒有快取機制)
  • ❌ 功能有限(主要是版本管理)
  • ❌ 維護不活躍(已轉交給 Nx 團隊)

適用場景: 小型項目,簡單的版本管理需求

2️⃣ Rush:微軟出品,企業級方案

優勢:

// rush.json - 強大的配置能力
{
  "projects": [
    { "packageName": "ui-lib", "projectFolder": "packages/ui" }
  ],
  "pnpmOptions": {
    "strictPeerDependencies": true
  }
}

特點:

  • ✅ 嚴格的依賴管理
  • ✅ 企業級特性完善
  • ✅ 支持 pnpm

劣勢:

  • ❌ 學習曲線陡峭
  • ❌ 配置複雜
  • ❌ 社區相對小眾

適用場景: 大型企業項目,需要嚴格管理

3️⃣ Nx:功能最強大的方案

優勢:

# 強大的代碼生成
nx generate @nx/react:component Button

# 智能的依賴圖分析
nx graph

# 高效的快取
nx run-many --target=build --all

特點:

  • ✅ 功能最豐富(代碼生成、依賴圖、插件系統)
  • ✅ 性能優秀(智能快取)
  • ✅ 支持多種框架(React、Vue、Angular)

劣勢:

  • ❌ 學習成本高
  • ❌ 配置複雜
  • ❌ 上手門檻高

適用場景: 大型項目,需要完整的工具鏈支持

4️⃣ Turborepo:我的最終選擇 🏆

核心優勢:

📈 極致的性能

真實項目數據對比
                無快取    有快取    提升倍數
Lerna:         45s       45s       1x
Rush:          38s       12s       3.2x
Nx:            35s       2.5s      14x
Turborepo:     9s        0.45s     20x ⚡
# Turborepo 在快取命中時快了 19-20 倍!

🎯 極簡的配置

Turborepo 配置:

// turbo.json - 僅需 76 行配置
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    }
  }
}

對比 Nx 配置:

// nx.json + workspace.json + project.json
// 需要 200+ 行配置

🔥 零配置開箱即用

# 3 步搞定
npx create-turbo@latest
cd my-turborepo
pnpm install

# 就這麼簡單!

⚡ 智能快取機制

# 第一次構建
pnpm build
✓ @company/utils built in 2.1s
✓ @company/ui built in 3.4s

# 代碼沒變化,再次構建
pnpm build
✓ @company/utils cached ⚡
✓ @company/ui cached ⚡
# 完成時間:0.3s!

🎨 我的技術選型過程

項目需求分析

GDU Common 項目特點:
✓ 4 個包(ui、utils、shared、controls-sdk)
✓ 都使用 Vue 3 + TypeScript
✓ 需要頻繁聯調
✓ 團隊 5-8 人
✓ 需要快速迭代

決策樹

開始
  ↓
需要 Monorepo? → 是
  ↓
團隊規模? → 5-8人(中小型)
  ↓
是否需要代碼生成? → 否
  ↓
是否需要多框架支持? → 否(只用 Vue)
  ↓
最看重什麼? → 性能 + 簡單
  ↓
選擇:pnpm + Turborepo ✅

選型理由

1️⃣ pnpm workspace

為什麼不選 npm/yarn?

# npm workspaces 的問題
npm install
# 幽靈依賴問題
# 速度較慢

# yarn workspaces 的問題  
yarn install
# 依賴提升導致的版本衝突
# PnP 模式不夠成熟

# pnpm workspace 的優勢
pnpm install
# ✅ 快速
# ✅ 嚴格
# ✅ 節省空間

pnpm-workspace.yaml 配置:

packages:
  - packages/*
  - docs
  - build

就這麼簡單!

2️⃣ Turborepo

為什麼不選 Nx?

# Nx 的問題
- 配置複雜(3-4 個配置文件)
- 學習曲線陡
- 功能過於豐富(我們用不上)

# Turborepo 的優勢
- 配置簡單(1 個 turbo.json)
- 性能極致(Go 語言編寫)
- 專注於構建(做好一件事)

為什麼不選 Lerna?

# Lerna 的問題
- 性能差(無快取機制)
- 功能有限
- 維護不活躍

# 數據對比
Lerna:     45s 構建
Turborepo: 9s 構建(無快取)
          0.45s 構建(有快取)

# 差距太明顯了!

🛠️ pnpm 深度解析

核心原理:基於符號連結的依賴管理

傳統的 node_modules 結構(npm/yarn)

node_modules/
├── package-a/
│   ├── index.js
│   └── node_modules/
│       └── package-b/  # 依賴被提升到頂層
├── package-b/          # 重複了!
└── package-c/

問題:

  • 依賴提升導致幽靈依賴
  • 重複的依賴佔用空間

pnpm 的 content-addressable 存儲

node_modules/
├── .pnpm/
│   ├── [email protected]/
│   │   └── node_modules/
│   │       ├── package-a/ → ~/..pnpm-store/...
│   │       └── package-b/ → .pnpm/[email protected]/...
│   └── [email protected]/
│       └── node_modules/
│           └── package-b/ → ~/.pnpm-store/...
└── package-a/ → .pnpm/[email protected]/...

優勢:

  • ✅ 扁平的 node_modules,但嚴格的依賴隔離
  • ✅ 全球存儲,硬鏈接復用
  • ✅ 避免幽靈依賴

實戰配置

package.json:

{
  "name": "gdu-common",
  "private": true,
  "scripts": {
    "install": "pnpm install"
  }
}

pnpm-workspace.yaml:

packages:
  - packages/*
  - docs
  - build

.npmrc 配置:

# 使用嚴格的 peer 依賴檢查
strict-peer-dependencies=true

# 不要幽靈依賴
shamefully-hoist=false

# 使用硬鏈接
link-workspace-packages=true

常用命令

# 安裝依賴
pnpm install

# 添加依賴到根目錄
pnpm add -w lodash-es

# 添加依賴到特定包
pnpm add vue --filter @gdu-common/ui

# 運行所有包的腳本
pnpm -r build

# 只運行特定包
pnpm --filter @gdu-common/ui build

⚡ Turborepo 深度解析

核心概念

1. 任務編排(Task Orchestration)

// turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],  // ^ 表示依賴包的 build
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["build"],   // 先 build 再 test
      "outputs": ["coverage/**"]
    }
  }
}

依賴圖:

@gdu-common/ui:build
  ↓ 依賴
@gdu-common/utils:build
  ↓ 依賴
@gdu-common/shared:build
# Turborepo 會自動計算正確的執行順序

2. 智能快取(Smart Caching)

快取鍵計算:

# Turborepo 會基於這些內容計算快取鍵
- 源代碼的哈希值
- 依賴的哈希值
- 環境變數
- 任務配置

# 任何一個變化,快取失效

快取命中示例:

$ pnpm build

Tasks:    4 successful, 4 total
Cached:   4 cached, 4 total ⚡
  Time:   450ms >>> FULL TURBO
# 4 個包全部命中快取,只用了 450ms!

3. 並行執行(Parallel Execution)

# Turborepo 自動分析依賴關係,最大化並行
                時間軸 →
shared:build    ▓▓▓
                  ↓
utils:build       ▓▓▓▓
                    ↓
ui:build            ▓▓▓▓▓
docs:build        ▓▓▓▓▓▓▓▓
# shared 和 docs 可以並行
# utils 等待 shared 完成
# ui 等待 utils 完成

真实性能數據

我的項目構建性能:

場景 時間 快取命中 說明
首次構建 9.2s 0/4 無快取
完全快取 450ms 4/4 ⚡ FULL TURBO
修改 1 個包 2.3s 3/4 增量構建
修改配置文件 9.1s 0/4 配置變化,快取失效

效率提升:

  • 完全快取時提升 20.4 倍 🚀
  • 日常開發平均提升 4-5 倍

Turborepo 配置實戰

基礎配置:

{
  "$schema": "https://turbo.build/schema.json",
  "ui": "tui",  // 使用終端 UI
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".vitepress/dist/**"],
      "cache": true
    },
    "lint": {
      "cache": true
    },
    "lint:fix": {
      "cache": false  // 修改文件的任務不快取
    },
    "clean": {
      "cache": false
    }
  }
}

高級配置:

{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": [
        "$TURBO_DEFAULT$",
        "!{dist,build,coverage,.turbo}/**",
        "!**/*.md",
        "!**/*.test.{ts,tsx}"
      ],
      "outputs": ["dist/**"],
      "cache": true
    }
  },
  "globalDependencies": [
    ".env",
    "tsconfig.json",
    "eslint.config.js"
  ],
  "globalEnv": [
    "NODE_ENV",
    "CI"
  ]
}

🎯 最終選擇:pnpm + Turborepo

組合優勢

pnpm workspace (包管理)
    +
Turborepo (構建編排)
    =
完美組合 🎉

1. pnpm 負責依賴管理

  • 快速安裝
  • 節省空間
  • 嚴格隔離

2. Turborepo 負責構建編排

  • 智能快取
  • 並行執行
  • 增量構建

3. 強強聯合

# pnpm 快速安裝依賴
pnpm install  # 12s

# Turborepo 快速構建
pnpm build    # 9s(首次) / 0.45s(快取)

# 總時間:13s(首次) / 12.5s(快取)

實際效果

開發效率提升:

# 傳統 Multirepo 工作流
修改共享函數 → 發布 → 更新依賴 → 重新安裝 → 測試
總耗時:5-10 分鐘 😫

# Monorepo + Turborepo 工作流
修改共享函數 → 保存 → 自動重建 → 熱更新
總耗時:2-3 秒 ⚡

# 效率提升:100-200 倍!

CI/CD 性能:

# .gitlab-ci.yml
build:
  script:
    - pnpm install          # 3s
    - pnpm build            # 9s (首次)
    # 後續 pipeline 只需 0.5s!

💡 選型建議

根據項目規模選擇

小型項目(2-3 個包)

✅ 推薦:pnpm workspace
❌ 不需要:Turborepo

# 理由:包少,構建快,不需要複雜的編排

中型項目(4-10 個包)

✅ 推薦:pnpm + Turborepo
⭐ 最佳組合!

# 理由:快取和並行構建帶來明顯收益

大型項目(10+ 個包)

✅ 推薦:pnpm + Turborepo
或
✅ 推薦:pnpm + Nx

# Nx 提供更多功能(代碼生成、依賴圖)
# Turborepo 更簡單,性能更好
# 根據團隊技術儲備選擇

根據團隊特點選擇

團隊特點 推薦方案
前端團隊,技術棧統一 pnpm + Turborepo
全棧團隊,多技術棧 pnpm + Nx
大型企業,嚴格管理 pnpm + Rush
簡單項目,快速上手 pnpm workspace

🚀 快速體驗

創建一個 Turborepo 項目

# 使用官方腳手架
npx create-turbo@latest my-monorepo

# 選擇 pnpm
? Which package manager do you want to use? › pnpm

# 項目結構
my-monorepo/
├── apps/
│   ├── web/
│   └── docs/
├── packages/
│   ├── ui/
│   └── eslint-config/
├── turbo.json
└── package.json

運行命令

# 安裝依賴
pnpm install

# 構建所有包
pnpm build

# 查看快取效果
pnpm build  # 第二次運行,體驗閃電般的速度 ⚡

📊 成本收益分析

遷移成本

項目 學習成本 遷移時間 配置複雜度
Lerna 1 天 2-3 天
Rush 3-5 天 1-2 周
Nx 5-7 天 1-2 周
Turborepo 半天 1-2 天

長期收益

開發效率:

  • 跨包重構時間減少 80%
  • 本地構建時間減少 90%(快取命中)
  • CI/CD 時間減少 70%

維護成本:

  • 配置文件減少 75%(統一管理)
  • 依賴衝突減少 90%
  • 版本管理複雜度降低 80%

團隊協作:

  • 代碼審查效率提升 50%
  • 跨項目問題定位快 3 倍
  • 新人上手時間減少 60%

🎉 總結

經過詳細的對比和實踐,我選擇了 pnpm + Turborepo 組合,理由是:

pnpm 的三大優勢

  1. - 安裝速度比 npm 快 3.75 倍
  2. - 節省 70% 磁碟空間
  3. - 杜絕幽靈依賴,依賴管理更安全

Turborepo 的三大優勢

  1. 極致性能 - 快取命中時快 20 倍
  2. 🎯 極簡配置 - 一個 turbo.json 搞定
  3. 🚀 零學習成本 - 半天上手,開箱即用

實際收益

  • 📈 構建速度提升 20 倍(快取命中)
  • 💾 磁碟空間節省 70%
  • ⏱️ 開發效率提升 100 倍(跨包修改)

在下一篇文章中,我將手把手帶你從零搭建一個完整的 pnpm + Turborepo 項目,包括:

  • 項目初始化
  • 包結構設計
  • 配置文件詳解
  • 第一個 Hello World 包

🔗 系列文章


你的項目用的是什麼 Monorepo 工具?效果如何?歡迎在評論區分享! 🙏

覺得 pnpm + Turborepo 組合不錯?點個讚收藏一下,下篇文章將實戰搭建! 👍


原文出處:https://juejin.cn/post/7561907345338122240


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝27   💬9   ❤️7
680
🥈
我愛JS
📝3   💬13   ❤️6
238
🥉
御魂
💬1  
4
#4
2
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付