认识 Vite 构建工具

142 阅读6分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情

什么是 Vite

Vite 法语的意思是快速的,发音是 veet。它是一种新型的前端构建工具,能够显著的提升我们前端开发者的体验。它主要由两部分组成:一个开发服务器,它基于原生的 ES 模块,提供了丰富的内建功能,如速度快到惊人的模块热更新 HMR。它提供一套构建指令,使用 Rollup 打包你的代码,并且它是预构建的,可输出用于生产环境的高度优化过的静态资源,Vite 旨在提供开箱即用的配置。但同时它也提供插件 API 和 JavaScript API 带来高度的可扩展性,并且有完整的类型的支持。

了解了什么是 Vite 之后,接下来我们就来回答为什么选择使用 Vite ?

为什么选用 Vite

在浏览器支持 ES 模块之前,JavaScript 并没有提供原生的机制,让我们开发者以模块化的方式进行开发。这也正是我们对打包这个概念熟悉的原因。

打包工作具体就是使用工具抓取处理,并将我们的源代码模块串联成可以在浏览器中运行的文件。

时过境迁,我们已经见证了很多这样的打包工具,比如 Webpack、Rollup、 Parcel 等这样的工具,它们极大的改善了我们前端开发者的开发体验。

然而,当我们开始构建越来越大型的应用的时候,需要处理的 JavaScript 的代码量也呈指数级增长。包含数千个模块的大型项目相当的普遍,我们开始遇到了性能瓶颈,也就是使用 JavaScript 的开发工具,通常需要很长时间甚至到几分钟才能启动我们的开发服务器。即使我们使用了 HMR,文件修改后的效果也需要几秒钟以后在浏览器中才能反映出来。

如此循环往复,迟钝的反馈,极大的影响了我们开发者的开发效率和开发幸福感。那具体表现在缓慢的服务器启动以及缓慢的更新两个方面。我们先来分析一下传统的打包方式,为什么服务器启动慢。

当我们做冷启动开发服务器的时候,下图是官网给的示意图。它是基于打包器的方式来启动的,它必须优先抓取构建我们的整个应用,才能提供服务。

image.png

这个问题主要体现在依赖和源码两个方面改进了开发服务器启动时间。

依赖方面:大多数的依赖都是在开发的时候不变动的一些纯的 JavaScript 代码,并且一些较大的依赖处理代价也很高。例如有上百个模块组件库。那依赖也通常存在多种模块化的格式,比如 ESM 或者是 CommonJS 这样的格式等等。

源码方面:我们的业务源码通常包含一些并不是纯的 JavaScript 的文件,这些文件可能还需要转换,时长还要被编辑。比如 JSX、CSS 或者是 Vue、React 组件。同时并不是所有的源码都需要同时的被加载,例如基于路由的拆分的代码模块。

传统的打包器需要构建整个应用,这种对依赖和源码的处理方式,势必会导致服务器启动缓慢。

那接下来我们再分析一下更新慢的原因。基于打包器启动时重建,整个包的效率是很低的。原因也显而易见,因为这样更新速度会随着应用体积的增长而直线的下降,一些打包器的开发服务器将构建内容存入内存,比如 Webpack 就是这样处理的。

这样它们只需要在文件更改的时候,使模块的一部分失,但它仍需要整个重新构建并重载页面,这样的代价是很高的,并且重新加载页面也会消除应用的当前状态。所以打包器支持了动态模块热重载,也就是我们熟知的 HMR。

它允许一个模块热替换它自己,而不会影响页面的其余部分,这就大大的改进了开发体验。比如 webpack-dev-server 就提供了 HMR 这样的功能。

然而在实践中,我们发现即使采用了 HMR 这种模式,其热更新的速度也会随着应用规模的增长而显著的下降。

那我们来看看 Vite 是如何实现快速的服务器启动以及快速的更新。

Vite 是利用生态系统中的新进展来解决上述问题的。也就是浏览器开始原生的支持 ES 模块,并且越来越多的 JavaScript 工具使用编译型的语言来编写。

快速的服务器启动:关于快速的服务器启动,官网也给了一张示意图。

image.png Vite 通过在一开始就将应用中的模块区分为依赖和源码两类,改进了开发服务器启动时间

Vite 将会使用 ESBuild 来构建依赖,ESBuild 使用 Go 语言来编写,并且比 JavaScript 编写的打包器预构建的依赖快 10~100 倍。

另外,Vite 以原生的 ESM 方式提供源码,这实际上是让浏览器接管了打包程序的部分工作。Vite 只需要在浏览器请求源码的时候进行转换,并按需提供源码。根据场景动态的导入代码,也就是只在当前屏幕上实际使用时才会被处理。

快速更新:在快速更新方面,Vite 的 HRM 是在原生的 ESM 上执行的。当编辑一个文件的时候,Vite 只需精确的使已编辑的模块与其最近的 HMR 边界之间的链失活。使得无论应用大小如何,HMR 始终保持快速更新,因为大多数的时候只是模块本身被更新了。

Vite 同时利用 HTTP 头来加速整个页面的重新加载,源码模块的请求会根据 304 来进行协商缓存。而依赖模块的请求会通过 Cache-Control 来进行强缓存。因此一旦被缓存,它们将不需要再次请求。说白了就是再次让浏览器为我们做更多的事情   那一旦你体验到 Vite 的神速,你是否还愿意再忍受像曾经那样的打包器来开发项目呢?