工程效率与质量 / 进阶
Monorepo 不只是把仓库放在一起:用工作区守住模块边界
从目录职责、依赖方向和发布边界出发,搭建一个不会随着项目增长而失控的 Monorepo。
先定义职责,再创建 packages
Monorepo 最常见的问题不是包太多,而是每个包都能随意引用其他包。先把应用、业务能力、基础设施和纯工具分层,再规定依赖只能由上层流向下层。目录名只是提示,真正的边界还要交给 lint 规则和持续集成验证。
EXAMPLE / 01Monorepo
apps/
web/
admin/
packages/
domain-order/
ui/
config-eslint/
config-typescript/让依赖关系可以被机器检查
给内部包统一使用 workspace 协议,避免本地开发和发布版本不一致。再通过 ESLint 的 import/no-restricted-paths 或 dependency-cruiser 声明禁止方向,例如 UI 包不能反向依赖具体业务包。
子包用到的依赖必须写进自己的 package.json。不要因为依赖被提升到根目录就省略声明,否则切换包管理器或独立发布时会立即暴露问题。
EXAMPLE / 02Monorepo
{
"dependencies": {
"@repo/domain-order": "workspace:^",
"@repo/ui": "workspace:^"
}
}只构建受影响的部分
缓存和增量构建只有在任务输入定义准确时才可靠。构建任务应包含源码、配置和依赖包输出;测试任务通常还要包含测试配置。先保证缓存命中不会返回错误结果,再追求流水线速度。
内部包拥有明确的 exports;CI 检查循环依赖和越层引用;变更集只发布真正变化的包;从干净环境验证一次完整安装与构建。