Vite原理浅析

Vite原理浅析
最新回答
假扮的天使

2023-05-31 14:17:41

Vite原理浅析

Vite是一种新型的前端构建工具,它基于ESBuild和Rollup,旨在解决当前前端工程化中的痛点,特别是缓慢的服务启动和更新问题。以下是对Vite原理的详细解析:

一、当前工程化的痛点

在浏览器支持ES Module之前,JavaScript并没有提供原生机制让开发者以模块化的方式进行开发。因此,打包工具应运而生,它们抓取、处理并将源码模块串联成可以在浏览器中运行的文件。然而,随着前端应用的不断增大,需要处理的JavaScript代码量也呈指数级增长,导致开发者遇到性能瓶颈。常用的打包工具如webpack,在开发环境下需要先将整个应用构建打包后,再把打包后的代码交给dev server,首次启动非常慢。此外,即使支持了HMR(Hot Module Replacement)热更新,但当项目中的文件变动时,打包器会对相关的依赖重新打包,热更新的速度也会随着程序体积的增长而显著下降。

二、Vite的解决之道

Vite利用前端生态中的新进展,特别是浏览器开始原生支持ES Module,以及越来越多的前端工具使用编译型语言编写(如ESBuild的Go和SWC的Rust),来解决上述问题。

  1. 解决缓慢的启动

    Vite直接将转换后的ES Module代码扔给支持前首ES Module的浏览器,利用浏览器对ES Module的支持(通过script标签加上属性type="module"),让浏览器自己去加载。浏览器直接向dev server逐个请求各个模块,而不慧尘数需要提前将所有文件进行打包,从而达到项目快速启动的效果。

    Vite将应用中的模块分为依赖和源码两部分。依赖大多为开发时不会变动的纯JavaScript,Vite使用ESBuild预构建依赖,借助ESBuild超快的编译速度对第三方库进行构建,一方面将零散的文件预构建打包到一起,减少网络请求;另一方面全面转换ES Module语法,以适配浏览器内置的ES Module支持。源码则通常包含一兄拦些并非直接是JavaScript的文件,如CSS等,这些文件需要转换,且时常会被编辑。Vite以原生ES Module的方式提供源码,让浏览器接管了打包的部分工作,Vite只需要在浏览器请求源码时进行转换并按需提供源码即可。

  2. 解决缓慢的更新

    Vite中的HMR是在原生ES Module上执行的。当编辑一个文件时,Vite只需要精确地使已编辑的模块与其最近的HMR边界之间的连接失活(大多数只是模块本身),不用重新构建整个应用,即可完成模块的热更新。这使得无论应用的大小如何,HMR都能始终保持快速更新。同时,Vite利用浏览器缓存来加速整个页面的重新加载:源码模块的请求会根据304 Not Modified进行协商缓存,而依赖模块则会通过Cache-Control进行强制缓存,一旦被缓存它们将不会再次请求。

三、Vite的简介与特点

Vite主要由开发构建和生产构建两部分组成。开发构建基于浏览器原生的ES Module能力来提供源文件,同时内置了高效的HMR。生产构建则使用Rollup进行打包,Vite提供指令来优化构建打包过程。

Vite的特点包括:

  • 快速的冷启动:通过No Bundle + ESBuild预构建实现。
  • 即时的模块热更新:基于ES Module的HMR,同时利用浏览器缓存策略提升速度。
  • 真正的按需加载:利用浏览器对ES Module的支持,实现真正的按需加载。

四、Vite的原理

  1. 请求拦截原理

    当声明一个script标签类型为module时,浏览器会解析资源并发起HTTP请求获取main.js文件。然后发现main.js内部含有import引入的模块,所以又会发起HTTP请求获取模块的内容。Vite在启动项目阶段会启动一个Koa dev server拦截浏览器对ES Module的请求,dev server对模块进行处理后,将模块加载到浏览器中即可。因此跳过了整体打包的阶段,而且是按需加载的。

  2. 重写模块路径

    由于浏览器只能识别./、../这样开头的相对路径以及/开头的绝对路径,而开发过程中经常会引入node_modules下的模块,浏览器无法识别和加载。因此Vite的dev server在请求拦截时通过es-module-lexer和magic-string这两个库对模块的路径进行重写。

  3. HMR原理

    Vite的热更新原理是在客户端与服务端之间建立了一个websocket链接监听文件的改变。当文件被修改时,dev server发送消息通知客户端修改相应的代码。客户端根据推送消息的类型执行不同的更新操作。

五、Vite的优化

  1. 依赖预构建

    Vite会对依赖进行预构建有两个原因:一是为了兼容CommonJS和UMD发布的依赖项;二是为了减少模块和请求的数量,提高页面的加载性能。

  2. 缓存

    Vite使用文件系统缓存和浏览器缓存来优化性能。文件系统缓存将预构建的依赖缓存到node_modules/.vite,只有在package.json中的dependencies列表、包管理器的lockfile或vite.config.js相关字段发生更改时,才需要重新运行预构建。浏览器缓存则根据304 Not Modified进行协商缓存或Cache-Control进行强制缓存。

六、当前存在的问题

尽管Vite在前端构建工具中表现出色,但仍存在一些问题:

  • 对React的支持不如Vue全面。
  • 移动端浏览器的兼容性问题。
  • Vite生态不如webpack强大。

综上所述,Vite通过利用浏览器原生支持ES Module的能力以及高效的编译工具ESBuild,实现了快速的服务启动和更新。然而,它仍需要在生态支持和兼容性方面继续努力。