build
在 Monorepo 中打包(Build)和单体项目最大的区别在于:依赖关系和缓存策略。
如果你的 apps/web 依赖 packages/ui,你必须确保 packages/ui 先被处理(如果它需要编译),然后才能构建 apps/web。手动管理这个顺序会让人发疯,所以我们把指挥棒交给 Turborepo。
作为架构师,我将教你一套**“一次配置,自动调度”**的构建方案。
🏗️ 核心原理:拓扑排序与缓存
Turborepo 会做两件事:
- 拓扑分析:它看到
web依赖ui,所以它知道“如果ui变了,web也要重打;如果ui没变,直接复用缓存”。 - 并行执行:如果
apps/admin和apps/web互不依赖,它会同时启动两个进程打包,速度加倍。
🛠️ 第一步:配置“指挥中心” (turbo.json)
我们需要告诉 Turbo:“什么样的操作叫打包?”以及“打包出来的文件在哪里?”。
打开根目录的 turbo.json,确保 tasks 下有 build 配置:
JSON
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
// 1. 依赖配置:
// "^build" 意思是:在跑我的 build 之前,先跑我所有依赖项(dependencies)的 build
"dependsOn": ["^build"],
// 2. 输出配置 (关键!):
// 告诉 Turbo 打包生成的文件在哪里。
// 如果下次代码没变,Turbo 会直接把缓存里的这几个文件夹恢复出来,而不会真的去跑编译命令。
"outputs": ["dist/**", ".next/**", "build/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}⚙️ 第二步:配置各项目的脚本
Turbo 只是发号施令的,真正干活的还是每个项目自己的 package.json。
检查
apps/web/package.json: 确保里面有build命令(Vite 项目默认就有): JSON"scripts": { "build": "tsc && vite build", // ... }检查根目录
package.json: 我们需要一个总开关。 JSON"scripts": { "dev": "turbo dev", "build": "turbo build" // 👈 添加这一行 }
🚀 第三步:执行打包
回到终端(根目录),运行:
Bash
pnpm build观察终端输出,你会看到类似这样的神奇画面:
Plaintext
• Packages in scope: web, docs, ui ...
• Running build in 3 packages...
@repo/ui:build: cache miss, executing... <-- UI 库先跑(如果有构建步)
apps/web:build: cache miss, executing... <-- Web 应用接着跑
...
Tasks: 3 successful, 3 total
Cached: 0 cached, 3 total
Time: 4.532s⚡️ 第四步:见证缓存的力量 (Full Turbo)
现在,不要修改任何代码,再次运行 pnpm build。
你会发现耗时变成了 100ms 甚至更短,并且显示: >>> FULL TURBO
这是因为 Turbo 发现源码没变,直接把上次生成的 dist 文件夹从缓存里“复制”出来了。这在 CI/CD(自动化部署)中能节省大量的服务器时间和金钱。
📦 第五步:找到你的产物
打包完成后,文件并不是汇总在根目录,而是分散在各个子应用里:
- Web 应用的包:
apps/web/dist/ - Admin 应用的包:
apps/admin/dist/
🚢 进阶:如何部署?(Docker vs Nginx)
既然你之前问到了 Nginx 部署,这里有两个流派:
方案 A:手动/脚本部署 (Nginx)
这是最简单的。
- 在本地或 CI 服务器运行
pnpm build。 - 写一个脚本,把
apps/web/dist里的所有文件,上传到服务器的/var/www/web。 - 把
apps/admin/dist里的所有文件,上传到服务器的/var/www/admin。 - 配置 Nginx 指向这两个目录(参考我上一个回答的 Nginx 配置)。
方案 B:Docker 部署 (企业级推荐)
在 Monorepo 里写 Dockerfile 有个大坑:依赖提升。你不能只 Copy apps/web,因为它依赖根目录的 node_modules。
你需要用到 turbo prune(修剪)功能。
生成裁剪后的项目: Bash
# 这条命令会分析 apps/web 依赖什么,把没用的(比如 admin)剔除掉 # 然后生成一个纯净的 out 文件夹 npx turbo prune --scope=web --docker构建 Docker 镜像: 基于这个
out文件夹去构建 Docker 镜像,体积会非常小且干净。