Turbopack—进化版webpack,高性能语言下的前端构建工具之争

662 阅读5分钟

大家好这里是阳九 一个相信万物皆可手写的前端菜鸡

最近 Turbopack 也算是在前端构建领域的一大热门选手, 看来前端框架-构建之战依然火热,作为webpack的粉丝,这里来介绍一下号称"下一代Webpack"的这位嘉宾

Turbopack 由webpack原班人马和Next.js团队联合开发的新一代前端构建工具

不用说也知道,很明显它对标的就是Vite(esBuild+Rollup). 在JS已经无法满足各位攻城狮的开发体验时,esbuild的作者首先用GO写了一个快速的打包器,其构建速度直接从语言层面上干翻了webpack.

Dev server启动时间对比 (官网数据)

组件数webpackviteturbo
10003.404.800.87
500010.7019.203.00
1000020.1037.206.10
3000076.60109.5020.30

可以看到 Turbopack 的Dev server启动速度比 Vite 快 5.4 倍, 比webpack快4倍

代码更新对比(官网数据)

组件数webpack(HMR)viteturbo
10000.130.090.01
50000.390.090.01
100001.070.110.01
300003.400.260.01

可以看到 turbo比vite快5.8倍,比webpack快9倍

并且由于turbo的”改啥打包啥”的机制,无论多大的文件热更新都只需要0.1s

本地打包(处理大型应用)

"像Vite这样的工具,不会在开发模式下打包源代码,因为他们依赖于浏览器的ES模块系统,.

但是在大量网络请求下,多个ES模块会导致启动时间变慢, 对于浏览器来说,能够在尽可能少的网络请求中接收所需的代码,那么它的速度会更快

所以我们希望Turbopack将代码捆绑在开发服务器中,特别是对于大型应用程序."

增量计算(减少工作量)

有两种方法可以使流程更快:减少工作量或并行工作。

Turbo引擎还会缓存它完成的所有结果,它以最大速度完成最少的工作

Vite 通过在开发模式下使用本机 ESM 来最大限度地减少已完成的工作。

esbuild的代码针对一项任务进行了高度优化 - 快速捆绑。它没有HMR(热模块替换)

esbuild 是一个非常快的捆绑器,但是没有做很多缓存,导致重复工作

lazy bundle(优化启动时间)

next.js仅仅打包服务器请求的页面,也就是懒打包

例如跳转到 localhost:3000/page/user, 仅仅会打包此页面和其导入的模块

但是esBuild,因为没有将代码拆分成单个的模块,esBuild是从入口将项目整体打包,只能全有或者全无.

这样的策略使得turbo启动时非常快,只打包页面所需呈现的代码。然后以单个模块的形式传给浏览器

核心概念

这里引用Turbo官网的图来举例

image.png

首先会并行readFile读取api.ts和sdk.ts两个文件,将其bundle构建为一个模块,将两个模块concat链接起来

image.png

此时我们修改了sdk.ts的代码,turbopack接收到文件改变的事件, 我们会重新走一遍sdk.ts的构建流程(readFile-bundle-concat)

重点在于,链接concat的时候,api.ts没有改变,会直接从缓存中读取api的模块,与新的sdk模块进行链接

turbo的缓存储存在内存中,只有终止devServer时缓存才会被清除

之后,turbopack计划将缓存保存在Turborepo这样的远程缓存中,意味着它可以支持跨机器进行远程工作

将来,持久缓存将为更快的生产构建打开大门。通过记住跨运行 完成的工作,新的生产版本只能重建已更改的文件 - 可能会节省大量时间。

综合看来 turbopack继承了webpack的热模块替换思想,并且与webpack一样,拥有强大的插件机制。

页面级编译和请求级编译

Next之前会根据显示的页面编译对应的模块

而Turbopack更进一步,只编译请求的代码,比如只请求HTML,则只编译HTML

如果浏览器想要一些CSS,我们将只编译它 - 而不编译引用的图像。

迁移

turbopack作为webpack的继任者,团队提供支持wepack应用的所有工具, 目前还无法从webpack迁移到turbo,但是不提供1:1的API兼容性.

比如babel现在暂时不支持,但是未来会通过插件进行babel的支持

总结: 为什么快

  1. 首先webpack运行在node环境下,也就是使用JS进行编写,

webpack打包 首先会读js代码,转换为ast,识别出import和require等关键字, 解析路径,再进行构建.

也就是说,在构建的时候,会在JS代码和AST之间反复横跳, 这个过程是很慢的,

而vite使用的esBuild 通过算法优化了这个反复横跳的过程,但代价是不支持热模块替换HMR,要么全量要么没有。

  1. 由于JS语言特性,无法多线程运行,webpack的构建实际上是递归(栈结构调用函数)构建各个文件.

而vite(esBuild)和turbo使用的go和rust语言支持多线程, 大大提高构建速度。

  1. 再说turbo和esbuild rust语言本身又比go更快, 并且esbuild并没有给每个模块做缓存, 而turbo做了大量的缓存工作,这使得在turbopack构建大型项目时优势更大。 并且能做到点对点的模块更新(HMR)。