比 Webpack 快700倍的全新开源打包工具 - Turbopack
共 3382字,需浏览 7分钟
·
2022-11-03 21:36
Turbopack
是一个可以取代 Webpack 的新开源打包工具,使用 Rust 编写,号称比 Webpack 快700倍!!!
著名的基于 React 的服务端框架 Next.js 的开发者 Vercel 于10月26日举行了 Next.js Conf 2022
活动,发布了 Next.js 的最新版本 Next.js 13
,以及 Rust 制作的快速打包工具 Turbopack
。
打包工具是一种将大量的 JavaScript、TypeScript 和其他代码打包成一体的工具。对于使用大量库和组件的团队开发的大型 Web 应用程序来说,它是必不可少的。
此次发布的 Turbopack 是由 Webpack(最出名的打包工具)的开发者 Tobias Koppers 和其他参与 Vercel 的人共同开发的,该公司解释说,Turbopack 是 Webpack 的继承者。
Turbopack 的特点包括:它是一个用 Rust 编写的本地应用程序,并且在执行后有一个重用内容的机制,这使得即使是大型的应用程序也可以更快地启动和运行。
在 Next.js 13
中,Turbopack 将成为默认的打包工具。
基于 JavaScript 的工具面临性能限制
曾几何时,用 JavaScript 编写这些工具是很自然的事情,Babel、tercer 和 Webpack 等工具就是这样创建的。
然而,随着前端应用程序的规模和复杂性的增加,使用这些基于 JavaScript 的工具进行编译开始遇到性能问题。
因此,在我们上次的活动中,我们已经开始迁移到基于 Rust 的原生工具。首先,我们从 Babel 迁移并将编译速度提高了 17 倍,接下来,通过替换 tercer,压缩速度提高了 6 倍。
Turbopack - Webpack 的继承者
打包工具 Webpack 已被下载超过30亿次,是我们打包构建过程中不可或缺的部分。Webpack 开发人员 Tobias Koppers 加入 Vercel,组建了一支世界一流的工程师团队,以创建下一代打包工具 - Turbopack,该团队吸取了 Webpack 10 年的经验教训,结合了 Turborepo 和 Google 的 Bazel 在增量计算方面的创新,并创建了一个可以支持未来几十年计算的架构。
对于大型应用,Turbopack 比 Vite 快 10 倍,比 Webpack 快 700 倍,更大的应用程序将使差异更大。
这种加速不仅在更新代码时很有用,而且在建立本地开发服务器时也很有用。
让我们看一个例子:即使是处理一个具有 3000 个模块的大型应用程序,Turbopack 也能在 1.8 秒内启动,比以前版本的 Next.js 和其他流行工具都更快。
增强本地和云端构建
Turbopack 的性能得益于其高度优化的机器代码和用 Rust 开发的低级增量引擎,Turbopack 对一个任务执行一次就不再执行。
Turbopack 最初将专注于本地开发体验,包括 React Fast Refresh
(注意:即使在应用程序运行时也能编辑组件),但最终将专注于加强 Next.js 在本地和云端构建。
与 Tuborepo 类似,你可以在你的团队中共享已经完成的工作,不仅在本地机器上,而且在你的整个组织中。
请务必升级到 Next.js 13 并运行 next dev --turbo
来试用 Turbopack 的 alpha 版本。
快速使用
到今天为止,Turbopack 可以在 Next.js v13 中使用,未来将发布独立的 CLI、插件 API,并支持其他框架,如 Svelte 和 Vue。现在,请按照以下说明开始:
使用 Turbopack 创建 Next.js v13 项目:
npx create-next-app --example with-turbopack
启动 Next.js 开发服务器(使用 Turbopack):
npm run dev
# 或者 yarn dev
Next.js v13 开发服务器现在由 Turbopack 提供支持!启动和更新都应该是近乎即时的,应用程序越大,改进就越大。
核心概念
让我们深入了解Turbopack的内部结构,弄清楚它为什么这么快。
Turbo引擎
Turbopack 之所以这么快,是因为它建立在一个可重复使用的 Rust 库上,这个库可以实现增量计算,也就是 Turbo 引擎。以下是它的工作原理。
函数级缓存
在 Turbo 引擎驱动的程序中,你可以将某些函数标记为"要记住的"
,当这些函数被调用时,Turbo 引擎会记住它们被调用的内容,以及它们返回的内容。然后,它会将其保存在内存中缓存起来。
下面是一个简化的例子,说明这在 builder 中可能是什么样子。
我们首先在两个文件 api.ts
和 sdk.ts
上调用 readFile
,然后我们把这些文件打包,把它们串联起来,最后得到fullBundle
,所有这些函数调用的结果都被保存在缓存中供以后使用。
让我们想象一下,我们是在一个开发服务器上运行。你把 sdk.ts
文件保存在你的机器上,Turbopack 接收到文件系统事件,并知道它需要重新计算。
由于 sdk.ts
的结果已经改变,我们需要再次打包它,然后需要再次串联。
重要的是 api.ts
没有改变,我们可以从缓存中读取它的结果,并将其传递给 concat,所以我们不用再读它和重新打包它,从而节省了时间。
现在想象一下,在一个真正的 bundler 中,有成千上万的文件需要读取和转换需要执行,和上面一样的你可以通过记住函数调用的结果和不重做以前做过的工作来节省大量的工作。
缓存
目前,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,我们将只编译 CSS,不编译引用的图片。
如果我们使用本地 ESM,我们会得到类似的行为,除了 Native ESM 会产生大量对服务器的请求。使用请求级编译,我们既可以减少请求的数量,又可以使用本地速度来编译它们,这提供了明显的性能改进。
Git 仓库:https://github.com/vercel/turbo