Build Engineer 是一个构建工程技能,提供构建系统与 CI/CD 优化方面的专业能力,重点覆盖 monorepo 工具(Turborepo、Nx、Bazel)、打包器优化(Webpack/Vite/Rspack)与增量构建,目标是通过缓存、并行化与构建性能优化来提升开发速度。
适用场景
- 搭建 monorepo(pnpm workspaces + Turborepo/Nx)
- 优化缓慢的 CI 构建(远程缓存、分片)
- 因性能原因从 Webpack 迁移到 Vite/Rspack
- 配置高级 Bazel 构建规则(Starlark)
- 调试复杂依赖图或循环依赖
- 实现 "Affected" 构建(只测试变更部分)
工具选型
monorepo 工具:Turborepo 适合 JS/TS 生态,零配置、简单、Vercel 原生,但主要限于 JS,粒度不如 Bazel;Nx 面向企业级 JS/TS,插件强大、支持代码生成与图可视化,但配置更重、更固执;Bazel 面向多语言(Go/Java/JS),封闭式构建、可无限扩展,但学习曲线陡峭、配置复杂;pnpm Workspaces 适合简单项目,Node.js 原生、安装快,但不含任务编排(需配合 Turbo/Nx)。
打包器:优先开发速度(HMR)时,Web 应用可选 Vite(基于 ESModules,启动即用),遗留应用可选 Rspack(兼容 Webpack,Rust 速度);优先生产优化时,追求最大压缩可选 Webpack(插件生态成熟),追求速度可选 Rspack/Esbuild;库作者需要双产物(CJS/ESM)时可选 Rollup(tree-shaking 标准)。
需要升级到 devops-engineer 的红旗信号:CI 流水线超过 20 分钟;node_modules 超过 1GB(幻影依赖);本地可用但 CI 失败(环境漂移);构建产物(source map)中发现密钥。
核心工作流示例
Turborepo 设置(远程缓存):通过 turbo.json 定义 build/test/lint 任务及依赖与输出,使用 npx turbo link 链接 Vercel 远程缓存,在 CI 中设置 TURBO_TOKEN 与 TURBO_TEAM 环境变量,执行 turbo run build test lint,首次约 5 分钟,二次可降至 100ms(FULL TURBO)。
Nx Affected 命令:使用 nx graph 可视化依赖,使用 npx nx affected -t test --base=origin/main --head=HEAD 只测试受影响项目,用 npx nx affected -t lint --base=origin/main 只对受影响项目执行 lint。
Bazel 概念映射:package.json 对应 WORKSPACE / MODULE.bazel,script: build 对应 js_library(name = "build"),dependencies 对应 deps = ["//libs/utils"],node_modules 对应 npm_link_all_packages。BUILD.bazel 示例使用 load("@aspect_rules_js//js:defs.bzl", "js_library") 并声明 srcs 与 deps。
反模式
幻影依赖:本地 import foo from 'foo' 可用但 CI 失败,原因是包管理器提升但未在 package.json 声明,解决方式是使用 pnpm 严格模式,通过符号链接阻止访问未声明依赖。
循环依赖:Lib A 与 Lib B 互相导入,构建报错 "Maximum call stack exceeded" 或 "Undefined symbol",解决方式是抽取共享代码到 Lib C,并用 npx madge --circular . 检测。
提交 node_modules:仓库体积达 2GB,导致克隆缓慢、平台相关二进制损坏,解决方式是 .gitignore 包含 node_modules/、dist/、.turbo/、.next/。
质量清单
性能:启用并验证远程缓存(命中率 > 80%);任务尽可能并行(拓扑感知);生产产物经压缩与 tree-shaking。
可靠性:锁文件一致;干净 runner 上构建通过(无缓存);确定性(相同输入 = 相同哈希)。
可维护性:package.json 脚本标准化(dev、build、test、lint);依赖图无环(DAG);为新库/应用提供脚手架生成器。
示例
企业级 monorepo 迁移:500 名开发者、4 个 React 应用和 15 个共享库从多仓库迁移到 monorepo,选择 Nx,用 madge 可视化依赖,定义 ui、utils、data-access、features 分层,配置 Nx Cloud 远程缓存;结果 CI 构建时间从 45 分钟降至 8 分钟(提升 82%),代码重复减少 60%,affected 构建常低于 1 分钟。
Webpack 迁移到 Rspack:大型电商平台生产构建 12 分钟,先迁移开发构建并暂时保留 Webpack 生产构建,映射 loader、使用兼容插件、并行验证输出;结果开发服务器启动从 45s 降至 2s(96%),HMR 更新从 8s 降至 0.5s(94%),生产构建从 12m 降至 2m(83%),包体积从 2.4MB 降至 2.3MB(4%)。
分布式 CI 流水线分片:游戏公司 5000 个 E2E 测试需将 CI 从 90 分钟降至 15 分钟以内,将测试分为 20 个分片(每片约 250 个),用 Nx affected 只跑变更功能,配置自动扩缩 runner;使用 Playwright --shard 与矩阵策略(max-parallel: 10);结果 E2E 从 90m 降至 12m(87%),反馈循环低于 15 分钟,云 CI 成本降低 30%。
最佳实践
monorepo 架构:从第一天定义并强制项目边界;使用严格依赖规则防止循环依赖并强制方向性;用生成器自动化新项目创建;用 Changesets 或 Lerna 统一版本发布;为变更维护架构决策记录。
构建性能:先用 speed-measure-webpack-plugin 等工具分析瓶颈再优化;配置增量构建;并行执行;在各层实施激进缓存;定期用 bundlephobia 清理未使用依赖。
CI/CD:快速失败,先跑快测试;智能分片;缓存依赖、构建输出与测试结果;条件执行只跑受影响任务;流水线即代码。
工具选型:工具匹配生态;评估迁移总成本;关注社区健康;确保插件生态满足需求;考虑团队熟悉度与学习曲线。
安全与合规:不提交密钥并使用自动扫描;定期依赖漏洞扫描与自动修复;CI 凭据最小权限;确保构建可从源码复现;保留所有构建与部署活动的审计日志。