前端打包性能优化--vite
为什么选择 Vite
问题
在 ES 模块在浏览器中可用之前,开发人员没有以模块化方式编写 JavaScript 的本机机制。这就是为什么我们都熟悉“捆绑”的概念:使用工具来抓取、处理并将我们的源模块连接成可以在浏览器中运行的文件。
随着时间的推移,我们看到了 webpack、Rollup和Parcel等工具,它们极大地改善了前端开发人员的开发体验。
然而,随着我们开始构建越来越多雄心勃勃的应用程序,我们处理的 JavaScript 数量也呈指数级增长。大型项目包含数千个模块并不少见。我们开始遇到基于 JavaScript 的工具的性能瓶颈:启动开发服务器通常需要非常长的等待(有时长达几分钟!),即使使用 HMR,文件编辑也可能需要几秒钟才能反映在浏览器中。缓慢的反馈循环会极大地影响开发人员的生产力和幸福感。
Vite 旨在通过利用生态系统中的新进展来解决这些问题:浏览器中原生 ES 模块的可用性,以及以编译为原生语言编写的 JavaScript 工具的兴起。
服务器启动慢
在冷启动开发服务器时,基于捆绑器的构建设置必须急切地抓取并构建您的整个应用程序,然后才能为其提供服务。
Vite 通过首先将应用程序中的模块分为两类:依赖项和源代码来改进开发服务器的启动时间。
依赖项大多是纯 JavaScript,在开发过程中不会经常更改。一些大型依赖项(例如具有数百个模块的组件库)的处理成本也很高。依赖项也可以以各种模块格式(例如 ESM 或 CommonJS)交付。
Vite使用esbuild预先捆绑依赖项。Esbuild 是用 Go 编写的,预打包依赖项的速度比基于 JavaScript 的打包程序快 10-100 倍。
源代码通常包含需要转换的非纯 JavaScript(例如 JSX、CSS 或 Vue/Svelte 组件),并且会经常被编辑。此外,并非所有源代码都需要同时加载(例如,使用基于路由的代码拆分)。
Vite 通过原生 ESM提供源代码。这实质上是让浏览器接管打包器的部分工作:Vite 只需要在浏览器请求时按需转换和提供源代码。只有在当前屏幕上实际使用时,才会处理条件动态导入背后的代码。
缓慢更新
当在基于捆绑器的构建设置中编辑文件时,重建整个捆绑包的效率很低,原因很明显:更新速度将随着应用程序的大小线性下降。
在某些捆绑器中,开发服务器在内存中运行捆绑,因此它只需要在文件更改时使其模块图的一部分无效,但它仍然需要重新构建整个捆绑并重新加载网页。重建捆绑包可能会很昂贵,并且重新加载页面会破坏应用程序的当前状态。这就是为什么一些打包程序支持热模块替换 (HMR):允许模块“热替换”自身而不影响页面的其余部分。这极大地改进了 DX - 然而,在实践中,我们发现即使是 HMR 更新速度也会随着应用程序大小的增长而显着下降。
在 Vite 中,HMR 是在原生 ESM 上执行的。当一个文件被编辑时,Vite 只需要精确地使被编辑的模块和它最近的 HMR 边界之间的链失效(大多数时候只有模块本身),无论你的应用程序的大小如何,都可以持续快速地更新 HMR。
Vite 还利用 HTTP 头来加速整个页面的重新加载(同样,让浏览器为我们做更多的工作):源代码模块请求是有条件的304 Not Modified
,并且依赖模块请求被强缓存通过Cache-Control: max-age=31536000,immutable
,因此它们不会再次访问服务器一旦缓存。
一旦您体验到 Vite 的速度有多快,我们非常怀疑您是否愿意再次忍受捆绑开发。
发表评论
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。