前端 CI/CD 质量门禁设计
Lint、Type Check、Unit Test、E2E、Bundle 分析的流水线设计与分支策略。
pnpm workspace、Turborepo、Changesets 与大型前端 Monorepo 的边界设计与依赖治理。
Monorepo 是大型前端团队的标配,但「把所有代码放一个仓库」不等于 Monorepo。高级前端需要展示的是包边界设计、依赖治理和发布策略。
| 痛点 | Monorepo 解决方案 |
|---|---|
| 跨项目代码复用 | 共享 packages |
| 版本不一致 | 统一依赖版本 |
| 原子化变更 | 一个 PR 改多个包 |
| CI 效率 | 增量构建(Turborepo) |
| 代码审查 | 统一 PR 流程 |
monorepo/
├── apps/
│ ├── web/ # 主站 React 应用
│ ├── admin/ # 管理后台 Vue 应用
│ └── desktop/ # Electron 桌面端
├── packages/
│ ├── ui/ # 共享组件库
│ ├── utils/ # 工具函数
│ ├── config/ # 共享 ESLint/TS 配置
│ └── api-client/ # API 客户端 SDK
├── pnpm-workspace.yaml
├── turbo.json
└── package.json
# pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
// packages/ui/package.json
{
"name": "@company/ui",
"version": "1.0.0",
"main": "./src/index.ts",
"dependencies": {
"@company/utils": "workspace:*"
}
}
pnpm 的优势:
workspace:* 协议自动链接本地包// turbo.json
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {}
}
}
turbo run build --filter=...@company/web
→ 只构建 web 及其依赖链,跳过无关包
→ 缓存命中时直接跳过(远程缓存共享给 CI)
@company/config// packages/ui/src/index.ts — 只暴露公共 API
export { Button } from "./Button";
export { Modal } from "./Modal";
// 不 export 内部 utils
# 1. 开发者添加 changeset
pnpm changeset
# → 选择变更的包和 semver 类型
# 2. CI 自动创建 Version PR
# → 更新 package.json 版本 + CHANGELOG
# 3. 合并后自动发布到 npm
dependsOn 配置遗漏| 阶段 | 迁移前(Lerna + 无 cache) | Turbo + remote cache |
|---|---|---|
| 全量 build | 22min | 6min(cache hit 时 90s) |
| PR 增量 | 18min | 2–4min |
| 循环依赖检出 | 手动 | dependency-cruiser 在 CI block |
循环依赖案例:ui 引 utils,utils 又引 ui 的类型——抽 shared-types package 打断。
Remote cache 用 S3 兼容存储;main 分支 cache 优先,feature 分支 hit 率 ~70%。