Monorepo 工具链与依赖管理
🌐 Monorepo 让多个包共享一个仓库,优化依赖管理和代码共享。核心是势头分云和增量构建。
主流工具对比
| 工具 | 特点 | 适用场景 |
|---|---|---|
| pnpm workspaces | 内置,快速 | 小中型项目 |
| Turborepo | 增量构建 + 并行 | 需要构建性能的场景 |
| Nx | 功能最全 | 大型企业项目 |
| Lerna | 老牌子,历史包 | 旧项目升级 |
pnpm Workspaces 基础
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
项目结构:
├── apps/
│ ├── web/ package.json: { "name": "@myapp/web" }
│ └── admin/ package.json: { "name": "@myapp/admin" }
├── packages/
│ ├── ui/ package.json: { "name": "@myapp/ui" }
│ └── utils/ package.json: { "name": "@myapp/utils" }
└── package.json
内部包引用
// apps/web/package.json
{
"dependencies": {
"@myapp/ui": "workspace:*",
"@myapp/utils": "workspace:*"
}
}
Turborepo 配置
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"], // 先构建依赖
"outputs": ["dist/**"],
"cache": true
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"cache": true
},
"lint": {
"cache": true
},
"dev": {
"cache": false, // 开发服务不缓存
"persistent": true
}
}
}
常用命令
# 构建所有包
turborepo run build
# 只构建一个包
turborepo run build --filter=@myapp/web
# 并行执行,最多 4 个
turborepo run test --concurrency=4
# 强制重新构建(跳过缓存)
turborepo run build --force
版本管理与发布
Changesets 工作流
# 1. 开发完成后生成变更集
npx changeset add
# 选择受影响的包 → 输入更新类型 (patch/minor/major) → 描述
# 2. CI 自动创建发布 PR
# 3. 入主分支后自动发布
npx changeset publish
依赖管理最佳实践
- 共享 devDependencies 放根 package.json:减少重复
- 内部包用
workspace:*:发布前自动替换为实际版本号 - catalog 功能 (pnpm 9+):集中管理版本
# pnpm-workspace.yaml
catalog:
react: ^18.3.0
typescript: ^5.5.0
vite: ^5.4.0
常见误区
- 没有正确配置
outputs,导致 Turbo 缓存失效 - 内部包没有先构建就被引用,导致类型报错(
^build解决) - 将所有依赖都放到根 node_modules 而不是各包自己,导致版本冲突