Vite
vite 涉及到了哪些底层原理
ESM:Vite 使用了
ES Module
来管理和加载模块。ES 模块是 JavaScript 的标准模块系统,相比于传统的 CommonJS 或 AMD,ES 模块具有更好的静态分析能力和更高的性能。Vite 通过使用浏览器原生的 ES 模块加载器,可以实现按需加载和快速构建。HTTP/2:Vite 借助于现代浏览器的 HTTP/2 支持来实现
更高效的资源加载
。HTTP/2 支持多路复用
,可以同时请求多个资源
,避免了传统的 HTTP/1 中的队头阻塞问题,加快了资源加载速度
。编译器:Vite 使用了
自定义的编译器
来处理开发时的模块解析和转换
。它能够识别模块的依赖关系,并将模块转换为浏览器可直接执行的代码。Vite 的编译器支持热模块替换(HMR)
,可以在代码修改时自动更新浏览器中的页面,提高开发效率。中间件:Vite 使用了
基于 Koa 框架的中间件
来处理开发服务器。通过中间件,Vite 可以拦截和处理开发时的 HTTP 请求,并根据请求的路径返回相应的模块文件。中间件还可以处理各种开发时的特殊需求,如代理 API 请求、路由转发等。
vite 编译器的组成部分
esbuild:一个快速的 JavaScript 打包器,用于在开发阶段进行实时编译。esbuild 提供了快速的冷启动和热模块替换功能,能够极大地加快开发环境的构建速度。
Rollup:一个强大的 JavaScript 模块打包器,在生产构建阶段使用。Rollup 能够将源代码打包为最终可发布的文件,支持
代码分割
、Tree Shaking
等优化技术,生成更小、更高效的代码包。前端开发服务器:Vite 还提供了一个内置的开发服务器,用于提供开发环境下的静态文件服务和构建工具集成。这个服务器能够利用 esbuild 实现快速的编译和热模块替换,使开发者在开发过程中可以快速地预览和调试代码。
插件系统:Vite 通过插件系统来扩展其功能。开发者可以编写自定义的插件,用于处理特定的文件类型、引入额外的功能或者定制构建过程。插件系统使得 Vite 能够与各种前端框架和工具集成,并提供更灵活的开发体验。
为什么说 vite 比 webpack 要快
和 webpack 对比,为什么 vite 的冷启动、热启动、热更新都会快?这就要说说二者的区别。 使用 webpack 时,从 yarn start 命令启动,到最后页面展示,需要经历的过程:
以 entry 配置项为起点,做一个全量的打包,并生成一个入口文件 index.html 文件; 启动一个 node 服务; 打开浏览器,去访问入 index.html,然后去加载已经打包好的 js、css 文件;
在整个工作过程中,最重要的就是第一步中的全量打包,中间涉及到构建 module graph (涉及到大量度文件操作、文件内容解析、文件内容转换)、chunk 构建,这个需要消耗大量的时间。尽管在二次启动、热更新过程中,在构建 module graph 中可以充分利用缓存,但随着项目的规模越来越大,整个开发体验也越来越差。
在浏览器支持 ES 模块之前,JavaScript 并没有提供原生机制让开发者以模块化的方式进行开发。这也正是我们对 “打包” 这个概念熟悉的原因:使用工具抓取、处理并将我们的源码模块串联成可以在浏览器中运行的文件。诸如 webpack、Rollup 和 Parcel 等工具应运而生。 Vite 旨在利用生态系统中的新进展解决上述问题:浏览器开始原生支持 ES 模块,且越来越多 JavaScript 工具使用编译型语言编写。
使用 vite 时, 从 vite 命令启动,到最后的页面展示,需要经历的过程:
- 使用 esbuild 预构建依赖,提前将项目的第三方依赖格式化为 ESM 模块;
- 启动一个 node 服务;
- 打开浏览器,去访问 index.html;
- 基于浏览器已经支持原生的 ESM 模块, 逐步去加载入口文件以及入口文件的依赖模块。浏览器发起请求以后,dev server 端会通过 middlewares 对请求做拦截,然后对源文件做 resolve、load、transform、parse 操作,然后再将转换以后的内容发送给浏览器。
在第四步中,vite 需要逐步去加载入口文件以及入口文件的依赖模块,但在实际应用中,这个过程中涉及的模块的数量级并不大,需要的时间也较短。而且在分析模块的依赖关系时, vite 采用的是 esbuild,esbuild 使用 Go 编写,比以 JavaScript 编写的打包器预构建依赖快 10-100 倍(webpack 就是采用 js )
综上,开发模式下 vite 比 webpack 快的原因:
- vite 不需要做全量的打包,这是比 webpack 要快的最主要的原因;
- vite 在解析模块依赖关系时,利用了 esbuild,更快(esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍);
- 按需加载;模块之间的依赖关系的解析由浏览器实现。Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。
- 充分利用缓存;Vite 利用 HTTP 头来加速整个页面的重新加载(再次让浏览器为我们做更多事情):源码模块的请求会根据 304 Not Modified 进行协商缓存,而依赖模块请求则会通过 Cache-Control: max-age=31536000,immutable 进行强缓存,因此一旦被缓存它们将不需要再次请求。