Appearance
Monorepo 架构分析
整体架构
Monorepo 采用工作空间(Workspace)架构,将多个包组织在一个仓库中。
┌─────────────────────────────────────────────┐
│ Monorepo Root │
├─────────────────────────────────────────────┤
│ 1. packages/ (包目录) │
│ ├── package-a/ │
│ ├── package-b/ │
│ └── package-c/ │
├─────────────────────────────────────────────┤
│ 2. apps/ (应用目录) │
│ ├── app-a/ │
│ └── app-b/ │
├─────────────────────────────────────────────┤
│ 3. tools/ (工具目录) │
│ ├── build/ │
│ └── test/ │
├─────────────────────────────────────────────┤
│ 4. config/ (配置目录) │
│ ├── lerna.json │
│ ├── nx.json │
│ └── turbo.json │
└─────────────────────────────────────────────┘核心组件
1. Workspace Manager
工作空间管理器负责管理所有工作空间。
职责:
- 管理工作空间
- 解析依赖关系
- 协调构建流程
关键方法:
javascript
class WorkspaceManager {
constructor(config) {
this.config = config
this.workspaces = new Map()
}
// 添加工作空间
addWorkspace(workspace) {
this.workspaces.set(workspace.name, workspace)
}
// 获取工作空间
getWorkspace(name) {
return this.workspaces.get(name)
}
// 获取所有工作空间
getWorkspaces() {
return Array.from(this.workspaces.values())
}
// 解析依赖关系
resolveDependencies() {
const graph = new DependencyGraph()
for (const workspace of this.workspaces.values()) {
graph.addNode(workspace.name, workspace)
for (const dep of workspace.dependencies) {
graph.addEdge(workspace.name, dep)
}
}
return graph
}
}2. Dependency Graph
依赖图管理包之间的依赖关系。
职责:
- 构建依赖图
- 检测循环依赖
- 计算构建顺序
关键方法:
javascript
class DependencyGraph {
constructor() {
this.nodes = new Map()
this.edges = new Map()
}
// 添加节点
addNode(name, workspace) {
this.nodes.set(name, workspace)
this.edges.set(name, new Set())
}
// 添加边
addEdge(from, to) {
if (this.edges.has(from)) {
this.edges.get(from).add(to)
}
}
// 获取依赖
getDependencies(name) {
return Array.from(this.edges.get(name) || [])
}
// 拓扑排序
topologicalSort() {
const visited = new Set()
const result = []
const visit = (name) => {
if (visited.has(name)) return
visited.add(name)
for (const dep of this.getDependencies(name)) {
visit(dep)
}
result.push(name)
}
for (const name of this.nodes.keys()) {
visit(name)
}
return result.reverse()
}
}3. Build System
构建系统负责协调构建流程。
职责:
- 并行构建
- 增量构建
- 缓存构建结果
关键方法:
javascript
class BuildSystem {
constructor(config) {
this.config = config
this.cache = new Map()
}
// 构建工作空间
async buildWorkspace(workspace) {
const cacheKey = this.getCacheKey(workspace)
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey)
}
const result = await this.buildInternal(workspace)
this.cache.set(cacheKey, result)
return result
}
// 构建所有工作空间
async buildAll(workspaces) {
const graph = this.resolveDependencies(workspaces)
const order = graph.topologicalSort()
const results = []
for (const name of order) {
const workspace = graph.getWorkspace(name)
const result = await this.buildWorkspace(workspace)
results.push(result)
}
return results
}
// 并行构建
async buildParallel(workspaces) {
const promises = workspaces.map(ws =>
this.buildWorkspace(ws)
)
return Promise.all(promises)
}
}依赖管理
依赖提升
将公共依赖提升到根目录:
packages/
package-a/
node_modules/
lodash/ (未提升)
package-b/
node_modules/
lodash/ (未提升)
提升后:
packages/
node_modules/
lodash/ (提升到根目录)
package-a/
package-b/依赖去重
去重重复的依赖:
javascript
function dedupeDependencies(workspaces) {
const versions = new Map()
for (const workspace of workspaces) {
for (const [name, version] of Object.entries(workspace.dependencies)) {
if (versions.has(name)) {
if (versions.get(name) !== version) {
console.warn(`版本冲突: ${name}`)
}
} else {
versions.set(name, version)
}
}
}
return versions
}构建优化
1. 并行构建
javascript
async function buildParallel(workspaces) {
const workers = os.cpus().length
const chunks = chunkArray(workspaces, workers)
const promises = chunks.map(chunk =>
Promise.all(chunk.map(ws => buildWorkspace(ws)))
)
return Promise.all(promises)
}2. 增量构建
javascript
async function buildIncremental(workspaces, changedFiles) {
const affected = getAffectedWorkspaces(workspaces, changedFiles)
for (const workspace of affected) {
await buildWorkspace(workspace)
}
}3. 缓存构建
javascript
class BuildCache {
constructor() {
this.cache = new Map()
}
get(key) {
return this.cache.get(key)
}
set(key, value) {
this.cache.set(key, value)
}
has(key) {
return this.cache.has(key)
}
}版本管理
语义化版本
javascript
function bumpVersion(version, type) {
const [major, minor, patch] = version.split('.').map(Number)
switch (type) {
case 'major':
return `${major + 1}.0.0`
case 'minor':
return `${major}.${minor + 1}.0`
case 'patch':
return `${major}.${minor}.${patch + 1}`
default:
return version
}
}版本同步
javascript
function syncVersions(workspaces, version) {
for (const workspace of workspaces) {
workspace.version = version
updatePackageJson(workspace)
}
}总结
Monorepo 的架构体现了以下特点:
- 工作空间:使用工作空间隔离项目
- 依赖图:管理包之间的依赖关系
- 并行构建:充分利用多核 CPU
- 缓存优化:缓存构建结果
理解 Monorepo 的架构有助于更好地使用和优化 Monorepo。
参考资源

扫描二维码关注"架构师AI杜"公众号,获取更多技术内容和最新动态
