
























打破误解:Monorepo 不只是前端专属,后端早已玩得炉火纯青
搜索“Monorepo”,铺天盖地都是 pnpm、Turborepo、前端组件库的内容,很容易让人产生一个错觉:Monorepo 是前端专属架构模式。作为一个全栈开发者,我曾长期抱有这样的误解,直到深入研究了各个语言生态后,才发现真相完全不同。
今天,我要分享三个关键洞察:
首先回答最实际的问题:没有 package.json,其他语言怎么搞 Monorepo?
<!-- 根目录 pom.xml -->
<project>
<groupId>com.company</groupId>
<artifactId>monorepo-root</artifactId>
<packaging>pom</packaging> <!-- 关键:pom 类型 -->
<modules>
<module>libs/common</module>
<module>services/user-service</module>
<module>services/order-service</module>
</modules>
</project>
Maven 通过 <modules> 标签定义多模块,子模块自动继承父级依赖版本,这其实就是 Java 版的“workspace”。
# 初始化工作空间
go work init
go work use ./services/user-service
go work use ./libs/common
# go.work 文件内容:
go 1.21
use (
./libs/common
./services/user-service
)
Go 1.18 正式引入 Workspace 特性,允许在单个仓库中管理多个模块,解决了本地开发时的模块替换问题。
# pyproject.toml (根目录)
[tool.poetry.workspace]
members = [
"libs/*",
"apps/*",
"services/*"
]
# 子项目引用本地依赖
[tool.poetry.dependencies]
common-lib = { path = "../../libs/common", develop = true }
Poetry 的 workspace 功能与 pnpm workspaces 异曲同工。
# BUILD.bazel 示例
java_library(
name = "common",
srcs = glob(["src/main/java/**/*.java"]),
)
go_binary(
name = "user_service",
srcs = ["main.go"],
deps = ["//libs/common:go_default_library"], # 跨语言依赖!
)
Google 开源的 Bazel 支持 Java、Go、Python、C++ 等多种语言,是真正的跨语言 Monorepo 构建系统。
理解了各语言的实现方式后,我们来看这个关键映射表:
| 前端概念 | Java 世界 | Go 世界 | Python 世界 | 通用术语 |
|---|---|---|---|---|
package.json |
pom.xml |
go.mod |
pyproject.toml |
项目配置 |
pnpm workspaces |
Maven Modules | Go Workspace | Poetry Workspace | 工作空间 |
node_modules |
~/.m2/repository |
GOPATH/pkg |
虚拟环境 | 依赖缓存 |
npm install |
mvn install |
go mod download |
poetry install |
依赖安装 |
"common": "workspace:*" |
${project.version} |
replace 指令 |
develop = true |
本地依赖 |
核心洞察:每个语言生态都有自己的实现,只是语法不同,概念完全相通。
这是最有趣的部分。根据我的观察和数据分析,原因有三:
前端社区擅长创造和推广新术语,同样的概念:
就像“云原生”概念一样,很多技术早已存在,但新术语让它们重新受到关注。
// 前端:工具即产品,需要营销
{
"Turborepo": "Vercel 的商业产品",
"Nx": "Nrwl 的商业产品",
"pnpm": "开源但需要推广",
"结果": "大量教程、博客、视频"
}
// 后端:工具即基础设施,低调务实
{
"Bazel": "Google 内部工具开源",
"Maven": "Apache 基金会项目",
"Gradle": "开源但企业导向",
"结果": "官方文档为主,营销内容少"
}
前端社区:
后端社区:
查看 Google Trends 会发现:
但这不代表后端用得少,只代表后端不这么叫。
# 现代全栈项目结构示例
fullstack-app/
├── apps/
│ ├── web/ # Next.js (TypeScript)
│ ├── mobile/ # React Native
│ └── admin/ # Vue.js
├── services/
│ ├── api/ # Go
│ ├── auth/ # Python
│ └── analytics/ # Java
├── packages/
│ ├── ui/ # 共享组件 (TS)
│ ├── schemas/ # 数据库模型 (多语言)
│ └── configs/ # 统一配置
└── infrastructure/ # Terraform, Docker
# Java 项目
推荐:Gradle Composite Builds
命令:gradle init --type java-library
# Go 项目
推荐:Go Workspace (1.18+)
命令:go work init && go work use ./...
# Python 项目
推荐:Poetry + Poetry Workspace
命令:poetry new --src my-package
# 多语言混合
推荐:Bazel 或 Nx
不要一次性重构成 Monorepo,而是:
别再只搜“Monorepo”,试试:
Monorepo 本质上是一种代码组织哲学,而不是某个特定工具或语言的特性。它解决的核心问题是:
前端社区让这个概念变得流行,但后端世界早已在实践中深耕多年。下一次当你看到“Monorepo”时,请记住:
希望这篇文章能打破你的信息偏差,让你在全栈开发中更加游刃有余。毕竟,好的架构思想应该是语言无关的。
扩展阅读:
欢迎在评论区分享你的 Monorepo 实践经验,无论是前端、后端还是全栈项目!
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。