用 Turborepo 打造 Strapi 插件开发的极速全栈体验
什么是Turborepo
我在两三年前听到这个名词一直没搞懂,今天我借助AI+实践搞懂了这个架构,以及我们为什么要用它
在现代前端工程化中,"Monorepo" 已经成为了一个绕不开的热词。但很多开发者在初次接触时,容易把它和 "Multirepo" 甚至 "Turborepo" 混淆
1. Multirepo:各自为政的“独栋别墅”
Multirepo (Multiple Repositories) 是最传统的管理方式。
🏠 比喻:你的前端团队住在 A 栋别墅,后端团队住在 B 栋别墅,UI 组件库团队住在 C 栋别墅。大家互不干扰,物理隔离。
这种模式是怎样的?
- 每个项目都有独立的 Git 仓库(例如
git/frontend,git/backend)。 - 每个仓库有自己独立的配置(ESLint, TSConfig)。
✅ 优点
- 权限清晰:你可以只给新人开前端仓库的权限,他看不到后端的代码。
-
体积小:
git clone很快,因为你只拉取了这一个项目的代码。
❌ 痛点
- 协作噩梦:当你修了一个 Bug,需要同时改动前端和后端代码时,你无法在一个 Commit 里完成。
-
依赖地狱:如果你改了
UI组件库的代码,你得先发个 npm 包,然后去前端项目里升级版本号,再npm install……这一套流程下来,一下午就过去了。
这种模式应该是目前大家所最常用的一种模式,这个主要是思维惯性与工具默认,早期的 CI/CD 工具(如 Jenkins)也更习惯于一个仓库对应一条流水线, 当你用 create-react-app 或 git init 时,默认就是创建一个仓库管一个项目
2. Monorepo:欢聚一堂的“大平层”
为了解决 Multirepo 的协作痛点,Google、Facebook 等大厂率先采用了 Monorepo (Monolithic Repository)。
🏢 比喻:大家搬进了一栋巨大的大平层公寓。虽然每人还有自己的房间(目录),但都在同一个大门(Git 仓库)里进出。
这种模式是怎样的?
-
所有项目都在同一个 Git 仓库里(例如
apps/web,apps/docs,packages/ui)。 - 使用 Workspace(工作区)技术将它们在本地软链接起来。
✅ 优点
- 原子提交 (Atomic Commits):你可以一次 Commit 同时修复前后端的 Bug,保证版本的一致性。
-
代码共享零成本:你在
packages/ui里改了按钮颜色,保存一下,apps/web里立马生效,根本不需要发包! - 统一规范:大家共用一套配置,从此不再有“你用 2 空格缩进,我用 4 空格”的争吵。
❌ 新的问题
- 构建太慢了! 以前你只构建一个项目,现在仓库里有 10 个项目。如果每次改一行代码,CI(持续集成)都要把 10 个项目全跑一遍,那就要等到天荒地老
在微服务架构流行之前(大概 2015 年以前),绝大多数项目(包括 JSP、ASP.NET、PHP)其实都是单体。那时候大家默认就是“一个仓库管所有代码”,根本不需要发明 Monorepo 这个词。后来,微服务和前后端分离流行起来了,大家把仓库拆散了(Multirepo)。再后来,大家发现拆太散了不好管,又把它们合并回来了,这时候为了区分“强耦合的单体”和“松耦合的多项目集合”,才强调了 Monorepo 这个概念
3. Turborepo:大平层的“智能管家”
这时候,Turborepo 登场了。
很多人的误区在于:“我要用 Turborepo 还是用 Monorepo?” 这是一个错误的问题。 Turborepo 不是 Monorepo 的替代品,而是它的加速器。
🤖 比喻:Turborepo 是这栋大平层公寓配备的AI 智能管家。
Turborepo 解决了什么?
它专门解决 Monorepo “构建慢、任务乱” 的问题。
⚡️ 核心黑科技 1:任务编排 (Pipeline)
它知道 web 应用依赖 ui 包。当你运行构建命令时,它会自动先构建 ui,而且能把互不相关的任务(比如 lint 和 test)利用多核 CPU 并行执行。
⚡️ 核心黑科技 2:智能缓存 (Caching)
这是 Turborepo 的杀手锏。当你运行构建时,它会先检查:“哎,这个文件之前构建过吗?输入变了吗?”
- 如果没变:直接从缓存复制粘贴结果。时间消耗:几毫秒。
- 甚至支持云端缓存:你同事构建过的结果,你拉下来也能直接用!
4. 项目实践
安装
pnpm dlx create-turbo@latest
以下是我工程目录
我们的目标目录结构如下:
my-strapi-monorepo/
├── apps/
│ ├── backend/ # Strapi v5 主程序
│ └── docs/ # VitePress 文档站
├── packages/
│ ├── strapi-plugin-bag/ # 我们的插件核心代码
│ └── ui/ # (可选) 共享 UI 组件库
├── package.json
├── pnpm-workspace.yaml
└── turbo.json
这种结构清晰地分离了“宿主应用”和“插件包”,模拟了真实的 npm 包引用场景。
统一依赖管理 (Workspace)
在根目录的 pnpm-workspace.yaml 中,我们将所有项目串联起来:
packages:
- "apps/*"
- "packages/*"
然后,在 apps/backend/package.json 中,我们可以直接引用本地插件,无需发包,无需 npm link:
"dependencies": {
"strapi-plugin-bag": "workspace:*"
}
这意味着,strapi-plugin-bag 的任何修改,对于 backend 来说都是实时可见的。
配置 turbo.json
这是 Turborepo 的大脑。我们需要告诉它,Strapi 的构建产物在哪里,以及哪些任务需要并行。
{
"$schema": "https://turborepo.com/schema.json",
"tasks": {
"build": {
// 依赖上游的 build (例如 backend 依赖插件先 build 完)
"dependsOn": ["^build"],
// 告诉 Turbo 哪些文件是产物,下次命中缓存直接恢复,不用真跑
"outputs": ["dist/**", "build/**", ".next/**"]
},
"dev": {
// 开发服务器不需要缓存,且需要持久化运行
"cache": false,
"persistent": true
}
}
}
小技巧:Strapi 的产物在 build/,插件在 dist/,VitePress 在 .vitepress/dist。确保把这些目录都加到 outputs 里,Turbo 的缓存才能生效。
一键启动全栈环境
在根目录运行:
pnpm dev
Turborepo 会自动寻找所有子项目中的 dev 脚本并并行执行:
- ✅ Backend: 启动 Strapi CMS (
http://localhost:1337) - ✅ Plugin: 开启 TypeScript 实时编译监听
- ✅ Docs: 启动 VitePress 文档 (
http://localhost:5173)
所有日志汇聚在一个终端,互不干扰,配合极好。
精准构建
只想重新构建插件?不需要跑整个仓库:
turbo run build --filter=strapi-plugin-bag
Turbo 的 --filter 参数非常强大,支持依赖拓扑筛选。比如 turbo run build --filter=backend... 会自动先构建 backend 依赖的所有包(插件),然后再构建 backend,--filter=等于项目名字(在package.json)
📝 总结
通过引入 Turborepo,我们将分散的 Strapi 插件开发流程整合成了一个有机的整体。
-
开发:
pnpm dev一键起飞。 - 调试:Workspace 软链接让源码修改即时生效。
- 文档:代码和文档同仓管理,版本同步更容易。
如果你也在做 Strapi 插件开发,强烈推荐尝试这种架构,它会让你从繁琐的 cd 命令中解放出来,专注于代码本身。
总结:该怎么选?
| 模式 | 适用场景 | 关键特点 |
|---|---|---|
| Multirepo | 团队完全隔离,技术栈无关,项目间几乎没有代码复用。 | 简单,但协作成本高。 |
| Monorepo | 全栈团队,前后端紧密协作,有公共组件库或工具库。 | 协作爽,代码复用率高。 |
| Turborepo | 只要你用了 Monorepo,就强烈建议用它! | 让 Monorepo 快得飞起。 |
一句话总结: Monorepo 是一种架构风格(把大家聚在一起),而 Turborepo 是工具(让大家聚在一起还能高效干活)