大家好这里是阳九 一个相信万物皆可手写的前端菜鸡
最近 Turbopack 也算是在前端构建领域的一大热门选手, 看来前端框架-构建之战依然火热,作为webpack的粉丝,这里来介绍一下号称"下一代Webpack"的这位嘉宾
Turbopack 由webpack原班人马和Next.js团队联合开发的新一代前端构建工具
不用说也知道,很明显它对标的就是Vite(esBuild+Rollup). 在JS已经无法满足各位攻城狮的开发体验时,esbuild的作者首先用GO写了一个快速的打包器,其构建速度直接从语言层面上干翻了webpack.
Dev server启动时间对比 (官网数据)
| 组件数 | webpack | vite | turbo |
|---|---|---|---|
| 1000 | 3.40 | 4.80 | 0.87 |
| 5000 | 10.70 | 19.20 | 3.00 |
| 10000 | 20.10 | 37.20 | 6.10 |
| 30000 | 76.60 | 109.50 | 20.30 |
可以看到 Turbopack 的Dev server启动速度比 Vite 快 5.4 倍, 比webpack快4倍
代码更新对比(官网数据)
| 组件数 | webpack(HMR) | vite | turbo |
|---|---|---|---|
| 1000 | 0.13 | 0.09 | 0.01 |
| 5000 | 0.39 | 0.09 | 0.01 |
| 10000 | 1.07 | 0.11 | 0.01 |
| 30000 | 3.40 | 0.26 | 0.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官网的图来举例
首先会并行readFile读取api.ts和sdk.ts两个文件,将其bundle构建为一个模块,将两个模块concat链接起来
此时我们修改了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的支持
总结: 为什么快
- 首先webpack运行在node环境下,也就是使用JS进行编写,
webpack打包 首先会读js代码,转换为ast,识别出import和require等关键字, 解析路径,再进行构建.
也就是说,在构建的时候,会在JS代码和AST之间反复横跳, 这个过程是很慢的,
而vite使用的esBuild 通过算法优化了这个反复横跳的过程,但代价是不支持热模块替换HMR,要么全量要么没有。
- 由于JS语言特性,无法多线程运行,webpack的构建实际上是递归(栈结构调用函数)构建各个文件.
而vite(esBuild)和turbo使用的go和rust语言支持多线程, 大大提高构建速度。
- 再说turbo和esbuild rust语言本身又比go更快, 并且esbuild并没有给每个模块做缓存, 而turbo做了大量的缓存工作,这使得在turbopack构建大型项目时优势更大。 并且能做到点对点的模块更新(HMR)。