從 Monorepo 開始:用 pnpm Workspace 與 Turborepo 統一管理大型前端倉庫實戰指南

如果你維護過三個以上的前端專案,一定遇過這種場景:公共工具函式改了一行,得同時到三個倉庫各改一次、各發一次版;A 專案升了 TypeScript 5.4,B 專案還卡在 4.9,型別對不上;想抽共用元件,只能複製貼上,貼著貼著兩邊就分家了。這些痛點的標準解法,就是今天的主角——Monorepo。

一、什麼是 Monorepo?先分清三個名詞

Monorepo 就是把多個專案或套件,放進同一個 Git 倉庫統一管理。它和兩個容易混淆的概念要區分:

  • Monorepo ≠ 巨石應用(Monolith):Monolith 是「一個應用包辦所有功能」;Monorepo 是「一個倉庫管理多個套件」,套件之間依然邊界清晰
  • Polyrepo(一倉庫一專案)的痛點:跨倉庫改代碼要發版多次、依賴版本各自漂移、共用代碼只能靠複製
  • 大廠都在用:Google、Meta 內部都是巨型 Monorepo;前端圈熟悉的 Vben Admin 本身就是 pnpm Monorepo 架構

重點:Monorepo 解決的是「代碼共享與一致性」問題,不是效能問題。把八竿子打不著的專案硬塞一個倉庫,只會拖慢 clone 和 CI。

二、步驟 1:用 pnpm Workspace 搭骨架

先安裝 pnpm(建議用 corepack),然後在專案根目錄建立 pnpm-workspace.yaml:

packages:
  - "apps/*"
  - "packages/*"

接著建立這樣的目錄結構:

my-monorepo/
├─ apps/
│  └─ web/          # 主應用(Vite + Vue3)
├─ packages/
│  ├─ utils/        # 共用工具庫
│  └─ ui/           # 共用元件庫
├─ package.json
└─ pnpm-workspace.yaml

關鍵一步:在 apps/web/package.json 裡用 workspace:* 協議引用本地套件:

{
  "dependencies": {
    "@my/utils": "workspace:*"
  }
}

執行 pnpm install 後,node_modules 裡的 @my/utils 會是一個指向本地目錄的 symlink。改了 utils 的代碼,web 這邊立刻生效,完全不用發版——這就是 workspace 協議的精髓:依賴的是「本地工作區的這個套件」,不是 npm 上的版本號。

三、步驟 2:用 Turborepo 加速任務調度

套件多了之後,build/lint 一個個跑太慢。Turborepo 會分析套件依賴圖,只重跑「真的變了」的部分。在根目錄初始化後配置 turbo.json:

{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

dependsOn: ["^build"] 表示「先把我依賴的套件 build 完再輪到我」——執行 pnpm turbo run build 時會自動先 build utils、再 build web。沒變化的套件直接命中快取,秒出結果;還可以用 filter 精準圈定範圍:

# 只對 web 及其依賴鏈跑建置
pnpm turbo run build --filter=web

重點:outputs 一定要寫對(如 dist/**),快取命中時 Turborepo 靠它還原產物;漏寫會出現「快取命中但檔案不存在」的靈異事件。

四、步驟 3:實戰抽共用元件與發版

把 formatDate、useDebounce 這類高頻工具放進 packages/utils 導出,apps 裡直接 import { useDebounce } from '@my/utils',配合 TypeScript 專案引用,型別即時可見。等元件庫要對外發佈時,再引入 Changesets 管版本號與 changelog——內部依賴用 workspace:*,對外發佈時自動替換成真實版本號。

五、三個邊界與避坑指南

  • 倉庫範圍:Monorepo 適合「強相關」專案——同一團隊、同一技術棧、高頻共享代碼;不同業務線的專案別硬湊
  • 依賴提升:pnpm 預設嚴格隔離 node_modules,子套件用了未宣告的依賴會直接報錯——這是好事,逼你把 dependency 寫乾淨
  • CI 範圍:用 Turborepo 的快取加 --filter,只建置受本次提交影響的套件,別每次全量跑,否則 CI 會越來越慢

總結:Monorepo 的本質是用「倉庫邊界」換「同步成本」——共享代碼即時可見、版本天然對齊,代價是工程化基建要自己搭好。pnpm Workspace 負責依賴拓撲,Turborepo 負責任務調度,兩者搭配就是目前前端圈的主流方案。

互動話題:你的團隊現在是 Polyrepo 還是 Monorepo?踩過哪些「共用代碼同步地獄」的坑?歡迎留言聊聊!