分享目的: 了解使用vite,了解其基本运行原理。后续计划引入block体系中。
一、why vite
现实问题
浏览器支持 ES 模块之前,JavaScript 并没有提供的原生机制让开发者以模块化的方式进行开发。因此产生了webpack,rollup等打包工具,
将我们的开发代码打包为在浏览器端能运行的代码。产生的问题是当项目越来越大,本地构建时间通常需要很久。
Vite 旨在利用浏览器开始原生支持 ES 模块解决此问题。
服务器启动缓慢
依赖:vite将使用esbuild将node_modules下的依赖进行打包。(Esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。)
源码: vite将jsx,vue等文件直接转化为浏览器能识别的esm形式文件。浏览器自己依据情景导入所需文件
更新缓慢
在实践中我们发现,即使采用了 HMR 模式,其热更新速度也会随着应用规模的增长而显著下降
在 Vite 中,HMR 是在原生 ESM 上执行的。当编辑一个文件时,Vite 只需要精确地使已编辑的模块与其最近的 HMR 边界之间的链失活(大多数时候只是模块本身),使得无论应用大小如何,HMR 始终能保持快速更新。
Vite 同时利用 HTTP 头来加速整个页面的重新加载,304缓存依赖模块。
为什么生产环境仍然需要打包?
尽管原生 ESM 现在得到了广泛支持,但由于嵌套导入会导致额外的网络往返,在生产环境中发布未打包的 ESM 仍然效率低下(即使使用 HTTP/2)。
为了在生产环境中获得最佳的加载性能,最好还是将代码进行 tree-shaking、懒加载和 chunk 分割(以获得更好的缓存)。
由于vite在启动的时候不需要打包,也就意味着不需要分析模块的依赖、不需要编译,因此启动速度非常快。
当浏览器请求某个模块时,再根据需要对模块内容进行编译。这种按需动态编译的方式,极大的缩减了编译时间,项目越复杂、模块越多,vite的优势越明显。
现象就是第一次加载会比较慢,刷新后加载较快
二、功能
依赖预构建
1.预构建 它们可以提高页面加载速度,并将 CommonJS / UMD 转换为 ESM 格式。
预构建这一步由 esbuild 执行,这使得 Vite 的冷启动时间比任何基于 JavaScript 的打包器都要快得多。
webpack 本身维护了一套模块系统,这套模块系统兼容了所有前端历史进程下的模块规范,包括 amd commonjs es6 等。
2.将每个文件中所需的依赖项重写,让浏览器能够找到对应依赖。
最终的代码都是交给浏览器执行的。vite更多的是利用了浏览器支持esm特性。
3.依赖是强缓存的,进一步利用了浏览器的特性,加速构建和加载过程。对比没有分包过的webpack,每次刷新页面都需重新加载整个js包。
同时vite会将打包后的文件放入node_modules下的 .vite文件,下次启动时直接使用缓存文件,当然也可以启动的时候加上 --force不使用缓存文件。实际两者差不不大,因为 esbuild 打包真的很快。
模块热重载
Vite 提供了一套原生 ESM 的 HMR API。 具有 HMR 功能的框架可以利用该 API 提供即时、准确的更新,而无需重新加载页面或清除应用程序状态。
开箱即用
typescript,jsx,vue,css预处理器,静态资源等都是开箱即用,不需要做相关loader等配置。
三、使用过程中碰到的问题
require语法无法支持
源代码中无法支持
解决方案: 手动将所有require方法重写为import导入
使用插件在vite编译时将require翻译为import
node_modules中无法支持
node_modules中require语法是支持的,但是require('xxx.css')是无法支持的。require is not defined
解决方案:重新打包相应模块,生成es文件,在packagejson中导入module字段配置。
window.require = () => {} 然后再在文件中import相关css文件(不推荐)。
todo:why node_moudles中能够支持require('xxx.js'),但是src中不行。
装饰器语法不支持
必须使用ts文件同时要在vite.config.js中作相关配置。
@vitejs/plugin-react 提供了相关react的插件。
其他奇奇怪怪问题
后续block/cli中实现的功能,通过vite的createServer实现。lion接入,html插入raptor,埋点。sso等等等