当前位置: 首页 > 科技观察

游禹锡:Turbopack真的比Vite快10倍吗?

时间:2023-03-17 01:08:36 科技观察

大家好,我叫CUGGZ。10月25日,Vercel推出了下一代打包工具:Turbopack,它是基于Rust的Webpack继承者,其文档中提到Turbopack比Vite快10倍。11月1日,Vue和Vite的作者尤雨熙发表了一篇文章《Is Turbopack really 10x Faster than Vite?》,对Turbopack和Vite进行了测试对比。下面一起来看看详情吧!在官方Turbopack文档的基准图中,最初显示带有Turbopack的Next13能够在0.01秒内执行React热模块替换(HMR),而Vite则需要0.09秒。上面还有冷启动性能基准测试,但由于没有冷启动基准测试显示出10倍的优势,我们只能假设“快10倍”的说法是基于HMR性能。Vercel没有在文档中包含任何指向他们用于生成这些结果的基准的链接。于是,裕达决定用新发布的Next13和Vite3.2来验证这些说法。测试的要点是通过测量两个时间戳之间的增量来比较HMR性能:修改源文件的时间,由单独的节点记录。now()调用直接记录在组件的渲染输出中。请注意,此调用发生在组件的虚拟DOM渲染阶段,因此它不受React协调或实际DOM更新的影响。该基准测试还测量了两种不同情况下的结果:根:根组件导入1000个不同的子组件并将它们一起呈现。leaf:叶子组件,该组件由根组件导入,但不导入组件(无子组件)。细微差别在测试这些之前,还有一些额外的细微差别值得一提:Next是否使用ReactServerComponents(RSC)。Vite是否使用SWC而不是Babel进行React转译。React服务器组件Next13引入了一个重大的架构转变,组件现在默认为服务器组件,除非用户使用“使用客户端”指令明确选择客户端模式。它不仅是默认设置,Next文档还建议用户尽可能保持服务器端模式以提高最终用户性能。第一轮测试(Nextw/RSC和Vitew/Babel))最初使用根和叶组件在服务器端模式下对Next13的HMR性能进行了基准测试。结果表明,Next13在这两种情况下实际上都比较慢,并且对于叶子组件来说差异显着,测试方法和测试结果如下。1.测试方法两个项目都是通过以下命令新建的:npxcreate-next-app@latestnpminitvite@latest#选择Reactpreset在每个项目中运行genFiles.(m)js生成1000个组件,所有组件都是导入的进入应用程序的根组件并一起呈现。对于每个项目,在单独的Node进程中运行watch.(m)js以获取文件更改的确切时间戳,用于标记HMR的开始。启动项目,并编辑以下文件来测试HMR:接下来:app/page.js(根组件)和app/comp0.jsx(叶组件)。Vite:src/App.jsx(根组件)和src/components/comp0.jsx(叶组件)。编辑的组件都在其输出中包含Date.now()。DOM中最终渲染的时间戳用于标记HMR的完成。2、测试结果记录5次以上。运行时间以毫秒为单位。第二轮测试(Nextw/oRSC和Vitew/Babel)在M1MacbookPro上测试)。在的情况下,对Next组件进行基准测试以使其相等。因此在Next根组件中增加了一个“useclient”指令来选择客户端模式。事实上,在客户端模式下,NextHMR有明显提升,比Vite快2倍,测试方法和测试结果如下。1.测试方法两个项目都是通过以下命令新建的:npxcreate-next-app@latestnpminitvite@latest#选择Reactpreset在每个项目中运行genFiles.(m)js生成1000个组件。所有组件都导入到应用程序的根组件中并一起呈现。将useclient指令添加到app/page.js以使其在客户端模式下呈现。这是确保正确比较所必需的,因为服务器端组件会产生不小的HMR开销(慢4倍)。对于每个项目,在单独的Node进程中运行watch.(m)js以获取文件更改的准确时间戳。这用于标记HMR的开始。启动项目,并编辑以下文件来测试HMR:接下来:app/page.js(根组件)和app/comp0.jsx(叶组件)。Vite:src/App.jsx(根组件)和src/components/comp0.jsx(叶组件)。2.以毫秒为单位记录超过5次运行时间的测试结果在M1MacbookPro上使用Babel转换测试SWC我们的目标是让基准测试只关注HMR性能差异,因此需要消除另一个变量:Vite默认的React预设使用Babel进行转译反应HMR和JSX。ReactHMR和JSX转换不是构建工具耦合功能,它可以通过Babel(基于JavaScript)或SWC(基于Rust)完成。Esbuild也可以转换JSX,但缺乏对HMR的支持。SWC比Babel快得多(单线程快20倍,多核快70倍)。Vite目前默认使用Babel的原因是安装大小和实用性之间的权衡。SWC的安装量相当大(node_modules有58MB,而Vite有19MB),许多用户仍然依赖Babel进行其他转换,因此Babel对他们来说是不可避免的。不过,这种情况未来可能会有所改变。Vite核心不依赖Babel,所以使用SWC代替Babel来处理React转换不需要对Vite进行任何更改,只需将默认的React插件替换为vite-plugin-swc-react-refresh即可。切换之后,可以看到Vite在根组件上有明显的提升,赶上了Next:有趣的是,这里的增长曲线显示Next/turbo在根组件上比在叶组件上慢了4倍,而Vite只是慢2.4倍。这意味着ViteHMR可以更好地扩展更大的组件。此外,切换到SWC还改进了Vite在Vercel基准测试中的冷启动指标。不同硬件上的性能由于这是一个涉及部分Node.js和本机Rust的综合基准测试,因此它在不同硬件上会有很大差异。以上结果是在M1MacBookPro上收集的。其他用户在不同的硬件上运行相同的基准测试并报告了不同的结果。在某些情况下,Vite的根组件速度更快,而在其他情况下,Vite在这两种情况下都明显更快。Vercel的澄清在Vercel发布自己的基准后,Vercel发布了一篇博客文章,阐明了他们的基准方法,并向公众提供了他们的基准以供验证。阅读文章和基准代码后,这里有一些关键点:Vite实现仍然使用默认的基于Babel的React插件。1000个组件案例的原始数字存在四舍五入问题——Turbopack的15毫秒四舍五入为0.01秒,Vite的87毫秒四舍五入为0.09秒。当原始数字接近6倍时,这被进一步宣传为10倍优势。Vercel的基准测试使用更新模块的“浏览器评估时间”作为结束时间戳,而不是React组件重新渲染时间。文章中的图表显示,当模块总数超过30k时,Turbopack可以比Vite快10倍。总之,如果满足以下所有条件,“比Vite快10倍”的说法就是正确的:Vite不使用相同的SWC转换。应用程序包含超过30k个模块。基准测试仅衡量热更新模块的评估时间,而不是实际应用更改的时间。什么是“公平”比较?如果我们要比较“开箱即用的默认值”,那么我们应该与Next中启用的RSC进行比较,因为这是默认值并且Next积极鼓励用户使用。由于Vercel的基准测试不使用RSC并且正在测量“模块评估时间”以排除由React的HMR运行时引起的差异,因此可以公平地假设基准测试的目标是比较Vite和Turbopack的原生HMR机制。不幸的是,在这个前提下,Vite仍然在基准测试中使用Babel,使得这种比较不平等。在使用Vite中的SWC更新比较结果之前,Turbopack比Vite快10倍的结论是不准确的。此外,我相信大多数人都会同意:30k模块对于绝大多数用户来说是一种极不可能出现的情况。使用SWC的Vite,实现10倍要求所需的模块数量可能变得更加不切实际。虽然理论上可行,但用它来推销Turbopack是不诚实的。用户更关心端到端的HMR性能,即从保存到看到变化的时间,而不是理论上的“模块评估”时间。当看到“更新速度提高10倍”时,普通用户会想到前者而不是后者,这是Vercel在其营销中忽略的警告。事实上,Next中服务器端组件(默认)的端到端HMR比Vite中的要慢。作为Vite的作者,很高兴看到像Vercel这样资金雄厚的公司投入巨资改进前端工具。在适用的情况下,未来甚至有可能在Vite中利用Turbopack。然而,开源工具的竞争应该建立在开放交流、公平比较和相互尊重的基础上,看到使用精心挑选的、未经同行评审、边缘误导性数字的激进营销令人失望和担忧,这些数字通常只出现在商业中竞争,相信Vercel可以做得更好。相关链接原文:https://github.com/yyx990803/vite-vs-next-turbo-hmr/discussions/8。代码:https://github.com/yyx990803/vite-vs-next-turbo-hmr。