02 工作区编排 本节摘要:OpenCode 是个有几十个包的大型单体仓库(monorepo)。这么多包怎么管?靠工作区(workspace)+ 任务编排。本节讲清这套编排:包之间怎么互相引用(工作区协议)、构建任务怎么增量(改一个包只重建受影响的)、为什么这种编排适合大型 monorepo。 一、几十个包的挑战 OpenCode 的源码不是一个包,而是几十个(模式层、协议层、服务端、领域核心、LLM、应用层、TUI、客户端、SDK、插件包......)。这带来几个挑战: 依赖管理:包 A 依赖包 B,怎么声明、怎么解析? 构建顺序:B 依赖 A,构建时得先建 A 再建 B。 增量构建:我改了 A,只重建 A 和依赖它的 B,不该全量重建。
本节摘要:OpenCode 是个有几十个包的大型单体仓库(monorepo)。这么多包怎么管?靠工作区(workspace)+ 任务编排。本节讲清这套编排:包之间怎么互相引用(工作区协议)、构建任务怎么增量(改一个包只重建受影响的)、为什么这种编排适合大型 monorepo。
OpenCode 的源码不是一个包,而是几十个(模式层、协议层、服务端、领域核心、LLM、应用层、TUI、客户端、SDK、插件包......)。这带来几个挑战:
这些挑战靠「工作区 + 任务编排」解决。
工作区是包管理器(Bun workspaces)的功能,让同一仓库里的包能互相引用,不用发布到 npm 再安装:
monorepo 根 ├─ packages/ │ ├─ schema/ (包 @opencode/schema) │ ├─ protocol/ (包 @opencode/protocol,依赖 @opencode/schema) │ ├─ core/ (包 @opencode/core,依赖 protocol+schema) │ └─ ... └─ package.json (声明工作区)
声明工作区后,包之间引用是「目录引用」——@opencode/protocol 依赖 @opencode/schema,解析时直接指向本仓库的 schema 目录,不走 npm。这让包间依赖「即时生效」——改了 schema,protocol 立刻能用上新代码,不用重装。
💡 工作区的价值:它让大型 monorepo 的包间依赖变得像「同一个项目里的模块引用」——即时、透明、无发布开销。这是大型项目能高效开发的基础。
多个包可能用同一个外部依赖(如某工具库)。如果各包各自声明版本,容易出现「A 用 v1、B 用 v2」的版本漂移。OpenCode 用**目录(catalog)**统一:
这和 OpenWork 教程讲的 catalog 是同一机制(两个项目都用 pnpm catalog)。版本统一避免了「同一依赖多版本共存」的怪问题。
有几十个包,全量构建很慢。任务编排工具(如 Turborepo)解决增量构建——它理解包间依赖,只重建受影响的:
你改了 schema 包 │ ▼ 任务编排分析依赖图 │ ▼ 找出谁依赖 schema: protocol, core, llm, ... (传递依赖) │ ▼ 只重建这些(及依赖它们的),其余跳过 │ ▼ 增量构建完成
这种「依赖图感知」的增量构建,让「改一个包」的重建范围最小化。对一个几十个包的仓库,这能把构建时间从「全量十几分钟」降到「增量几十秒」。
任务编排还解决「构建顺序」问题。包间有依赖(B 依赖 A),构建时得先建 A 再建 B。编排工具用拓扑排序——按依赖图算出合法的构建顺序:
依赖图: schema ← protocol ← core ← llm ← opencode │ ▼ 拓扑排序 构建顺序: schema → protocol → core → llm → opencode │ ▼ 按此顺序构建,保证被依赖的先建
这和你手动维护「先建谁后建谁」的脚本相比,是质的飞跃——加新包、改依赖,排序自动更新。
除了顺序,编排工具还能并行——没有依赖关系的包可以同时建(多核利用):
A、B 互不依赖 ──► 并行建(同时) │ C 依赖 A、B ──► 等 A、B 建完再建
这让大型仓库的构建充分利用多核,进一步加速。
总结这套编排为什么适合大型 monorepo:
| 挑战 | 编排如何解决 |
|---|---|
| 包间依赖 | 工作区目录引用,即时生效 |
| 版本漂移 | catalog 统一版本 |
| 全量构建慢 | 依赖图感知增量,只重建受影响 |
| 构建顺序 | 拓扑排序自动算 |
| 多核利用 | 无依赖包并行建 |
这五点合起来,让「几十个包的仓库」依然能高效开发——加包、改依赖、增量构建,都自动处理。这是 OpenCode 这种规模项目能持续演进的基础。
源码管理讲清了,下一节讲怎么把源码变成可执行——单文件构建。