Skip to content

build

在 Monorepo 中打包(Build)和单体项目最大的区别在于:依赖关系缓存策略

如果你的 apps/web 依赖 packages/ui,你必须确保 packages/ui 先被处理(如果它需要编译),然后才能构建 apps/web。手动管理这个顺序会让人发疯,所以我们把指挥棒交给 Turborepo

作为架构师,我将教你一套**“一次配置,自动调度”**的构建方案。

🏗️ 核心原理:拓扑排序与缓存

Turborepo 会做两件事:

  1. 拓扑分析:它看到 web 依赖 ui,所以它知道“如果 ui 变了,web 也要重打;如果 ui 没变,直接复用缓存”。
  2. 并行执行:如果 apps/adminapps/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

  1. 检查 apps/web/package.json: 确保里面有 build 命令(Vite 项目默认就有): JSON

    "scripts": {
      "build": "tsc && vite build", 
      // ...
    }
  2. 检查根目录 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)

这是最简单的。

  1. 在本地或 CI 服务器运行 pnpm build
  2. 写一个脚本,把 apps/web/dist 里的所有文件,上传到服务器的 /var/www/web
  3. apps/admin/dist 里的所有文件,上传到服务器的 /var/www/admin
  4. 配置 Nginx 指向这两个目录(参考我上一个回答的 Nginx 配置)。

方案 B:Docker 部署 (企业级推荐)

在 Monorepo 里写 Dockerfile 有个大坑:依赖提升。你不能只 Copy apps/web,因为它依赖根目录的 node_modules

你需要用到 turbo prune(修剪)功能。

  1. 生成裁剪后的项目Bash

    # 这条命令会分析 apps/web 依赖什么,把没用的(比如 admin)剔除掉
    # 然后生成一个纯净的 out 文件夹
    npx turbo prune --scope=web --docker
  2. 构建 Docker 镜像: 基于这个 out 文件夹去构建 Docker 镜像,体积会非常小且干净。