Turbopack 建立在新的增量架构上,以提供最快的开发体验。 在大型应用程序上,它显示更新速度比 Vite 快 10 倍,比 Webpack 快 700 倍。 在更大的应用程序上,差异更大——通常比 Vite 快 20 倍。
Turbopack 仅捆绑开发所需的最少资产,因此启动时间非常快。 在具有 3,000 个模块的应用程序上,Turbopack 需要 1.8 秒才能启动,而 Vite 需要 11.4 秒。
Turbopack 是针对 JavaScript 和 TypeScript 优化的增量打包器,由 Vercel 的 Webpack 和 Next.js 的创建者用 Rust 编写。
在大型应用程序上,Turbopack 的更新速度比 Vite 快 10 倍,比 Webpack 快 700 倍。对于最大的应用程序,差异变得更加明显,更新速度比 Vite 快 20 倍。
Turbopack 性能的秘诀是双重的:高度优化的机器代码和低级增量计算引擎,可以缓存到单个函数的级别。一旦 Turbopack 执行了一项任务,它就再也不会这样做了。
我们的团队吸取了 Webpack 10 年的经验教训,结合了 Turborepo 和 Google 的 Bazel 在增量计算方面的创新,并创建了一个可以支持未来几十年计算的架构。
Turbopack 目前处于 alpha 阶段。它还没有准备好用于生产。感谢您的支持和反馈,因为我们正在努力为每个人做好准备
核心概念
让我们深入了解 Turbopack 的内部结构,找出它为何如此之快。
涡轮发动机
Turbopack 之所以如此之快,是因为它建立在一个可重用的 Rust 库之上,该库支持称为 Turbo 引擎的增量计算。这是它的工作原理:
函数级缓存
在 Turbo 引擎驱动的程序中,您可以将某些功能标记为“要记住”。当这些函数被调用时,Turbo 引擎会记住它们被调用的内容,以及它们返回的内容。然后它将其保存在内存缓存中。
我们首先调用readFile
两个文件,api.ts
和sdk.ts
。然后我们将bundle
这些文件concat
放在一起,最后得到fullBundle
。所有这些函数调用的结果都保存在缓存中以备后用。
假设我们在开发服务器上运行。您将sdk.ts
文件保存在您的机器上。Turbopack
接收到文件系统事件,并知道它需要重新计算readFile("sdk.ts")
:
由于结果sdk.ts
已经改变,我们需要bundle
再次连接它,然后需要再次连接。
至关重要的是,api.ts
没有改变。我们从缓存中读取它的结果并将其传递给concat
。因此,我们通过不阅读并重新打包来节省时间。
现在想象一下,在一个真正的捆绑器中,有数千个文件要读取和转换要执行。心智模型是一样的。您可以通过记住函数调用的结果而不是重复以前完成的工作来节省大量工作。
缓存
Turbo 引擎当前将其缓存存储在内存中。这意味着缓存将与运行它的进程一样长 - 这对于开发服务器来说效果很好。在 Next v13 中运行next dev --turbo
时,您将使用 Turbo 引擎启动缓存。当您取消开发服务器时,缓存将被清除。
将来,我们计划将这个缓存持久化——要么保存到文件系统,要么保存到像 Turborepo 这样的远程缓存。这意味着 Turbopack 可以记住跨运行和机器完成的工作。
优势
这种方法使 Turbopack 在计算应用程序的增量更新方面非常快速。这优化了 Turbopack 以处理开发中的更新,这意味着您的开发服务器将始终快速响应更改。
未来,持久缓存将为更快的生产构建打开大门。通过记住跨运行完成的工作,新的生产构建只能重建更改的文件 - 可能会节省大量时间。
按需编译
Turbo 引擎有助于在您的开发服务器上提供极快的更新,但还有另一个重要指标需要考虑 - 启动时间。您的开发服务器开始运行的速度越快,您开始工作的速度就越快。
有两种方法可以使流程更快 - 工作更快,或做更少的工作。启动开发服务器,减少工作量的方法是只编译启动所需的代码。
页面级编译
2-3 年前的 Next.js 版本用于在显示您的开发服务器之前编译整个应用程序。在 Next.js [11] 中,我们开始只编译请求的页面的代码。
这更好,但并不完美。当您导航到 时/users,我们将捆绑所有客户端和服务器模块、动态导入的模块以及引用的 CSS 和图像。这意味着如果您的页面的很大一部分隐藏在视图之外,或者隐藏在选项卡后面,我们仍然会对其进行编译。
请求级编译
Turbopack 足够聪明,可以只编译您请求的代码。这意味着如果浏览器请求 HTML,我们只编译 HTML——而不是 HTML 引用的任何内容。
如果浏览器需要一些 CSS,我们将只编译它——而不编译引用的图像。背后有一个大的图表库next/dynamic
吗?在显示图表的选项卡显示之前不编译它。Turbopack 甚至知道不编译源映射,除非您的 Chrome DevTools 是打开的。
如果我们使用原生 ESM,我们会得到类似的行为。除了 Native ESM 向服务器产生大量请求外,正如我们为什么选择 Turbopack 部分所讨论的那样。通过请求级编译,我们既可以减少请求的数量,又可以使用本机速度来编译它们。正如您在我们的基准测试中看到的那样,这提供了显着的性能改进。