三年前我在与多伦多一位客户的通话中坐着,看着一个 Next.js 构建爬行式地花了 94 秒,我们两个人都装作习以为常。Webpack。八千个模块。一个含有共享 UI 组件的单代码库,自 2021 年以来就没人审计过。客户问我们能否"让它更快"。我报价两天的工作量。结果花了四天。即便如此,我们也只是把它降到了 61 秒,感觉就像赢了一场没人想参加的比赛。
Turbopack 改变了这个故事。大多数情况下。但在 2026 年的今天,我还是不断看到开发者认为切换到 Turbopack 是终点线,而不是起点。他们打开这个开关,砍掉开发服务器启动时间的 40%,就宣告完成。真正的瓶颈只是转移到了更隐蔽的地方。
所以让我带你走一遍在真实生产代码库中运行 Turbopack 时构建时间真正消耗的地方。不是待办事项应用。不是 Next.js 示例模板。一个真实网站,拥有 200 多条路由、CMS 集成,以及注意到每一秒的客户。
开发模式与生产构建之间的差距
这是大多数人忽视的地方:Turbopack 最大的胜利在于开发服务器。增量编译、模块级缓存、整个 Rust 驱动的图。在开发模式中,它确实具有变革性。我在一个 Seahawk 客户项目上记录了冷启动,从 webpack 下的 28 秒降至 Turbopack 下的不足 4 秒。这不是舍入误差。
但 next build 是另一回事。截至 2026 年初,Turbopack 的生产构建支持稳定但并未重写整个管道。静态分析、页面优化和 SWC 编译器都仍在与 Turbopack 的打包器并肩进行繁重工作。你不会在生产输出上获得统一的 10 倍收益。
这很重要,因为开发者基准测试的是错误的东西。他们看着 next dev 启动,得出构建很快的结论。然后 CI 花了 3 分钟,他们就耸肩。
Turbopack 架构实际上做什么
Turbopack 基于按需计算模型运行。它只构建被请求的内容,在模块级缓存,精确而非广泛地进行失效。这就是为什么 Vercel 团队的架构文档讨论"函数级记忆化"。这不是营销术语。这是为什么触及一个组件不会强制全部重新打包的真实机制。
含义:你最快的收益发生在失效范围之前过于宽泛的地方。共享工具文件、大型桶导出、深层嵌套重导出。这些是 Webpack 曾在默默惩罚你的地方。
2026 年时间究竟消失在哪里
我上个季度使用 NEXT_TURBOPACK_TRACING=1 审计了四个代码库。是的,这个环境变量存在,是的,它会吐出一个可以加载到 Chrome 性能面板的追踪文件。在假设任何特定东西是罪魁祸首之前强烈推荐这样做。
这是我的发现,大致按出现频率排列:
- 桶文件爆炸。一个
index.ts重导出设计系统中的 60 个组件,即使你只使用两个,也会将所有这些模块拉入图中。Turbopack 处理得比 Webpack 更好,但并未使问题消失。修复是粒度导入。始终如此。 - 未将类型检查与打包分离。在 Turbopack 正在处理的同一构建管道内运行
tsc --noEmit会加倍你的墙时间。分离它。TypeScript 类型检查和 Turbopack 打包应在 CI 中是并行作业,而不是顺序步骤。 - 第三方包中的不稳定模块 ID。一些 npm 包仍然附带 CommonJS 和动态 require。Turbopack 必须为这些回退到较慢的分析路径。我上个月用一个较旧版本的 PDF 生成库遇到了这个问题。升级它,节省了 8 秒。
- 构建时的图像优化。如果你用
next/image预生成数千个图像变体并进行静态导出,那是同步且受 CPU 限制的。这不是 Turbopack 的问题。但它会出现在构建追踪中,人们就怪起打包工具来了。 - 大型 `getStaticProps` 数据负载。在构建期间从 CMS 获取 4MB 的数据,跨越 300 个页面,这是网络和解析问题。同样,不是 Turbopack 的问题。但它存在于同一个 180 秒的构建中,被集体指责。
令人不适的真相是,Turbopack 加速了打包阶段,以至于周围的一切相比之下都显得缓慢。就像把你的厨房垃圾桶升级为自动打开,然后才意识到走到外面的大垃圾桶才是真正的不便。
桶文件问题值得单独讨论
我再强调也不为过。桶文件是我在各个代理商看到的最常见的自我造成的构建问题。
一个客户在 2025 年末来找我们,他们的组件库有这样的结构:
`` components/ index.ts (exports 140 named components) ``
每个页面即使只导入一个按钮,也会拉取整个 140 个组件的图。用 Webpack,树摇晃在输出时可以部分帮助。用 Turbopack,模块图仍然需要被遍历和理解才能删除任何东西。开发服务器本身不慢,但冷启动很痛苦。
我们重构为路径特定的导入:
`` import { Button } from '@company/ui/button' import { Modal } from '@company/ui/modal' ``
冷开发启动从 11 秒降至 3 秒以下。生产构建减少了 22 秒。没人碰 Turbopack 配置。修复就是……不懒惰地处理导入。
实际上有一个很好的 eslint-plugin-import 规则可以捕捉这些:import/no-barrel-files。把它加到你的 lint 配置中,把违规当作构建债务处理。
CI 中的缓存:你可能浪费了 40 秒
Turbopack 的本地缓存很优秀。CI 缓存是一个独立的问题,大多数团队设置一次就再也不看了。
Turbopack 缓存默认位于 .next/cache/turbopack。如果你的 CI 管道(GitHub Actions、CircleCI 或其他)在运行之间没有持久化这个目录,你每次都在做一个完整的冷构建。在任何合理规模的代码库中,那是每次运行 30 到 60 秒的纯浪费。
GitHub Actions 中 Next.js + Turbopack 设置的正确缓存密钥是这样的:
- 缓存密钥:
package-lock.json的哈希 +next.config.js的哈希 +tsconfig.json的哈希 - 缓存路径:
.next/cache - 恢复密钥:回退到同一分支上的前一个缓存,然后是 main
就这样。大多数团队只对 package-lock.json 做哈希。但如果你的 next.config.js 改变了 Turbopack 配置(实验性功能、模块别名、自定义加载器),你会想要它失效。我见过一个 bug,其中一个过时的缓存在配置改变后提供了不正确的模块解析。晚上 11 点调试起来很讨厌。
Seahawk 有一个金融科技项目,仅仅修复缓存密钥结构就把平均 CI 构建从 4 分 20 秒降至 2 分 50 秒。同样的代码。同样的硬件。只是更聪明的缓存失效。
自定义加载器以及它们为什么在杀死你的收益
Turbopack 支持自定义加载器,但有成本。每个自定义加载器都会让你脱离 Turbopack 的原生快速路径,进入兼容层。Vercel 团队在 Next.js Turbopack 配置文档中对此相当坦诚。
我最常在以下情况看到这个:
- SVG 加载器(人们在构建时将 SVG 转换为 React 组件)
- 带有大量 remark/rehype 插件链的 MDX
- 带有自定义 PostCSS 配置(包含少见插件)的 CSS Modules
对于 SVG,2026 年的做法是将图标库预编译为 React 组件作为独立的构建步骤,而不是在 Next.js 构建时进行。SVGR 作为独立脚本非常适合这种用途。当设计标记改变时运行它,提交输出,让 Turbopack 将它们视为常规 .tsx 文件。
MDX 更棘手一些。如果你运行 40 个 remark 插件,你会感受到性能影响。审计一下你实际需要的插件。我见过代码库运行了 remark-gfm、remark-smartypants、自定义脚注插件和另外两个,其中只有两个产生了可见的输出差异。删除未使用的那些。
没人谈论的模块解析税
路径别名。每个人都用。@/components、@/lib、~/utils。它们很方便。但也产生了小税收,会不断累积。
Turbopack 在每次导入时都要解析别名。在包含 4,000 个导入和 12 个配置别名的大型代码库中,那就是每次构建 48,000 次解析操作。不是灾难性的。但也不是免费的。
解决方案不是移除别名。而是对它们更精确。避免使用通配符别名模式,改用具体路径。保持你的 tsconfig.json 路径与 next.config.js turbopack resolveAlias 配置同步。这两者之间的偏差会导致 Turbopack 做冗余解析工作。仅清理这方面我就见过 4-5 秒的性能提升。
2026 年 Turbopack 仍然不做的事
我喜欢 Turbopack。我们在大多数新的 Seahawk 项目中使用它。但诚实很重要。
- 包分析不如 Webpack 生态那么成熟。
@next/bundle-analyzer能用,但可视化的粒度没有webpack-bundle-analyzer那么细。这在改进中,但还没到位。 - 插件生态更小。如果你的技术栈依赖高度定制的 Webpack 插件(一些遗留企业设置确实会),迁移仍然是一个真正的项目,而不是下午的工作。
- Windows 性能历来落后于 macOS 和 Linux。每个 Next.js 版本都在改进,但如果你的团队以 Windows 为主,迁移前先做基准测试。
这些都不是致命问题。但如果你在评估是迁移现有项目还是从零开始,这些都是真实的考虑。
如何真正追踪你的构建
别猜了。运行这个:
- 在环境中设置
NEXT_TURBOPACK_TRACING=1 - 运行 next build(或
next dev,如果你在分析开发启动) - 在 Perfetto UI 或 Chrome 的
chrome://tracing中打开 .next/trace - 按时长过滤。单个模块超过 2 秒的任何东西都值得深入调查。
这是我在任何构建优化工作之前的做法。追踪告诉你时间花在了哪里。其他一切都只是伪装成专业知识的猜测。
---
FAQ
2026 年 Turbopack 对生产构建足够稳定吗?
是的,生产构建支持在 2024 年末作为稳定版本发布,并在整个 2025 年显著成熟。对于大多数从零开始的 Next.js 项目,我会毫不犹豫地默认使用 Turbopack。对于具有大量 Webpack 定制的遗留项目,先做一个试验并进行测量。
Turbopack 会替代 SWC 吗?
不是。SWC 是 TypeScript 和 JSX 转译器。Turbopack 是打包工具。它们一起工作。Turbopack 内部使用 SWC 进行转换。你不需要在它们之间做出选择。
为什么我的 Turbopack 开发服务器很快,但 CI 构建仍然很慢?
几乎肯定是这些之一:类型检查与打包串行运行、CI 没有为 .next/cache 配置缓存,或图片优化主导了静态生成阶段。运行追踪。它会告诉你是哪一个。
我应该现在就把现有的 Webpack 项目迁移到 Turbopack 吗?
如果是全新项目或自定义程度低,可以。如果你有 15 个自定义 Webpack 插件和复杂的加载器链,预留一个专门的迁移冲刺。不要把它当作周五下午的临时工作。(我是从个人经历说的。别问我周五发生了什么。)
Turbopack 能与 Nx 或 Turborepo 单仓库一起工作吗?
可以,而且实际上效果很好。Turborepo 的缓存很好地堆叠在 Turbopack 的内部缓存之上,这两个工具源自同一个团队。对于每个 PR 只有部分包改变的大型单仓库,这种组合确实很好。
---
构建工具很无聊,直到你的 CI 账单每月 800 美元,你的开发团队在站会上抱怨冷启动。Turbopack 转移了瓶颈,这是进步。但它并没有消除需要清楚地思考时间流向的必要性。先追踪。再优化。看在一切的份上,修复你的 barrel 文件。
