10 月 25 日,Next.js 13 正式发布。同时,Vercel 还推出并开源了下一代打包工具:
Turbopack
。Turbopack 是针对 JavaScript 和 TypeScript 优化的增量打包工具,由 Webpack 的创建者 Tobias Koppers 和 Next.js 团队使用 Rust 编写。Turbopack 的推出吸引了众多开发者的关注,下面就来看看 Turbopack 都有哪些优势!
Turbopack 的速度有多快?
Turbopack 建立在新的增量架构上,以提供最快的开发体验。在大型应用上,它的更新速度比 Vite 快 10 倍,比Webpack 快 700 倍。在更大的应用上,通常会比 Vite 快 20 倍。
由于 Turbopack 只打包开发所需的最少资源,因此启动时间非常快。在具有 3000 个模块的应用上,Turbopack 需要 1.8 秒即可启动,而 Vite 则需要 11.4 秒:
Turbopack 为什么这么快?
Turbopack 性能的秘诀有两个:高度优化的机器代码和低层级增量计算引擎,可以缓存到单个函数的级别。它的架构吸取了 Turborepo 和 Google 的 Bazel 等工具的经验教训,它们都专注于使用缓存来避免重复执行相同的工作。
Turbo 引擎工作原理
Turbopack 之所以如此之快,是因为它建立在一个可重用的 Rust 库之上,该库支持增量计算,称为 Turbo 引擎。以下是它的工作原理。
在 Turbopack 驱动的程序中,可以将某些函数标记为“to be remembered”。当这些函数被调用时,Turbo 引擎会记住它们被调用的内容,以及它们返回的内容。然后它将其保存在内存缓存中。下面是一个简化的示例:
我们首先在
api.ts
和
sdk.ts
这两个文件中调用
readFile
。然后打包这些文件,将它们拼接在一起,最后得到 fullBundle。所有这些函数调用的结果都保存在缓存中以备后用。
由于
sdk.ts
的结果发生了变化,就需要再次打包,然后需要再次拼接。重要的是,
api.ts
并没有改变。只需从缓存中读取它的结果并将其传递给
concat
。因此,这样就通过不读取并重新打包来节省了时间。
Turbo 引擎当前将其缓存存储在内存中。这意味着缓存将与运行它的进程一样长,这对于 Dev server 来说效果很好。将来,计划将这个缓存持久化——要么保存到文件系统中,要么保存到像 Turborepo 这样的远程缓存中。这意味着 Turbopack 可以记住跨运行和机器完成的工作。
这种方法使 Turbopack 在计算应用的增量更新方面非常快速,优化了 Turbopack 以处理开发中的更新,这意味着 Dev server 将始终快速响应更改。
按要求编译
Turbo 引擎有助于在 Dev server 上提供极快的更新,但还有另一个重要指标需要考虑——
启动时间
。Dev server 开始运行的速度越快,开始工作的速度就越快。有两种方法可以使流程更快:工作更快或做工作更少。为了启动 Dev server,减少工作量的方法就是只编译启动所需的代码。
(1)页面级编译
2-3 年前的 Next.js 版本在显示 Dev server 之前会编译整个应用。从 Next.js 11 开始就只编译请求的页面上的代码。这样会更好,但并不完美。当导航到
/users
时,将打包所有客户端和服务端模块、动态导入的模块以及引用的 CSS 和图片。这意味着如果页面的很大一部分隐藏在视图之外,或者隐藏在选项卡后面,仍然会编译它。
(2)请求级编译
Turbopack 足够智能,可以只编译请求的代码。这意味着如果浏览器请求 HTML,就只会编译 HTML,而不会编译 HTML 引用的任何内容。如果浏览器需要 CSS,将只编译 CSS,而不编译其引用的图片,Turbopack 甚至知道不编译 source map,除非 Chrome DevTools 是打开的。通过请求级编译,减少了请求的数量,性能改进显着。
为什么基于 Rust 开发?
Turbopack是基于 Rust 开发的,每当 Next.js 团队将基于 JavaScript 的工具转移到基于 Rust 的工具时,都会看到巨大的改进。Next.js 替换了 JavaScript 编译器 Babel,使编译速度提高达 17 倍,替换了 Terser,使压缩速度提高了 6 倍,同时还减少了加载时间和宽带使用。
为什么选择 Turbopack?
创建 Turbopack 就是为了提高 Next.js 的速度,希望它能够取代 Webpack,成为下一代 Web 打包工具。那为什么不选择新一代打包工具 esbuild 和 swc,而是选择创建自己的打包工具呢?
增量计算
通常,有两种方法可以加快进程:减少工作量或并行工作。想要打造最快的打包工具,就要用力拉动这两个杠杆。因此决定为分布式和增量行为创建一个可重用的 Turbo 构建引擎。Turbo 引擎就像函数调用的调度程序一样工作,允许在所有可用内核上并行调用函数。Turbo 引擎还会缓存它调度的所有函数的结果,这意味着它永远不需要执行两次相同的工作。简而言之,
它会以最大速度做最少的工作
。
其他工具对“做更少的工作”采取不同的方式。比如,Vite 通过在开发模式下使用原生 ESM 将工作量降至最低。在底层,Vite 将 esbuild 用于许多任务。esbuild 是一个非常快的打包器,它不会强迫我们使用原生 ESM。但出于几个原因,决定不采用 esbuild:
-
esbuild 的代码针对一项任务进行了超优化 – 快速打包,因此没有 HMR(热更新);
-
esbuild 是一个非常快的打包工具,但它并没有做太多的缓存。这意味着会做很多重复的工作;
而具有增量计算的 Rust 驱动的打包器在更大的规模上可以比 esbuild 更好地执行。
惰性打包
Next.js 的早期版本试图在开发模式下打包整个 Web 应用,这并不是最优的。Next.js 的现代版本仅打包 Dev server 请求的页面。例如,如果转到
localhost:3000
,它将仅打包
pages/index.jsx
,以及它导入的模块。
这种更“惰性”的方法是快速 Dev server 的关键。而 esbuild 没有“惰性”打包的概念——它是全有或全无的。Turbopack 的开发模式会根据收到的请求构建应用导入和导出的最小图,并且只打包必要的最少代码。
此策略使 Turbopack 在首次启动 Dev server 时速度极快。只需计算渲染页面所需的代码,然后在单个块中将其发送到浏览器。在大规模应用中,这最终比原生 ESM 快得多。
这就是构建 Turbopack 的原因。
Turbopack 的功能
构建 Web 应用的实践非常多样化。仅在 CSS 中,就有 SCSS、Less、CSS Module、PostCSS等。React、Vue 和 Svelte 等框架需要自定义设置。
在构建打包工具时,我们希望它能开箱即用,无需配置,可以通过插件获得一些功能。目前,Turbopack 仍处于 alpha 阶段,在当前状态下,Turbopack 还不能配置,所以插件也还不可用。
下面来看一下 Turbopack 默认配置中哪些功能是开箱即用的以及未来将通过插件配置的功能:
-
JavaScript
:支持所有 ESNext 功能、Browserslist 和顶层 await; -
TypeScript
:开箱即用地支持 TypeScript,包括解析路径和
baseUrl
; -
Imports
:支持 require、import、动态导入等; -
Dev Server
:优化的 Dev Server 支持热更新 (HMR) 和快速刷新; -
CSS
:支持全局 CSS、CSS Module、postcss-nested 和
@import
; -
静态资源
:支持
/public
目录、JSON 导入和通过 ESM 导入资源; -
环境变量
:通过
.env
、
.env.local
等支持环境变量。
Turbopack vs Vite vs Webpack
Turbopack vs Vite
Turbopack 在以下两个关键指标上的表现优于 Vite。
(1)Dev server 启动时间
Turbopack 的 Dev server 启动速度比 Vite 快得多。在 1000 个模块的应用中,Vite 需要 4.8 秒才能启动。Turbopack 启动仅需 0.9 秒,快了5.5倍。在大型应用中,这种差异将保持一致。在 30000 个模块的应用中, Turbopack 的启动速度比 Vite 快了 5.4 倍。
(2)代码更新
当文件更改时,它需要将更改呈现给浏览器。它做到的越快,反馈循环就越紧密,发布的速度就越快。在 1000 个模块的应用中,Turbopack 对文件更改的速度比 Vite 快 5.8 倍。
Turbopack vs Webpack
Turbopack 的增量架构在以下两个关键指标上超过了 Webpack 的速度。
(1)Dev server 启动时间
Turbopack 的 Dev server 启动速度比 Webpack 快得多。Next.js 12 底层使用了 Webpack,可以在 3.4 秒内在 1000 个模块的应用上启动 build server。Turbopack 的启动速度快了 0.9 秒 – 3.9倍。
(2)代码更新
在 Dev server 上执行的最常见操作就是更改文件。当文件更改时,它需要将更改呈现给浏览器。它做到的越快,反馈循环就越紧密,发布的速度就越快。在 1000 个模块的应用中,Turbopack 对文件更改的反应速度比 Webpack 快 8.9 倍:
Turbopack 的未来
到目前为止,Turbopack 可以在 Next.js v13 中使用。未来将发布独立的 CLI、插件 API,并支持其他框架,如 Svelte 和 Vue。
Turbopack 将用于 Next.js 13 Dev server。它将为闪电般快速的 HMR 提供动力,并将原生支持 React 服务端组件,以及 TypeScript、JSX、CSS 等。Webpack 用户还可以期待使用 Turbopack 进入基于 Rust 的未来的增量迁移路径。
期待在 Webpack 的创建者 Tobias Koppers 的带领下,Turbopack 成为 Web 的下一代打包工具。
参考:
-
https://vercel.com/blog/turbopack
-
https://turbo.build/