跳到主要内容

Vite

2024年03月05日
柏拉文
越努力,越幸运

一、机制


1.1 Vite 原理?

开发环境: Vite 利用浏览器去解析 imports,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用(就相当于把我们在开发的文件转换成 ESM 格式直接发送给浏览器)。 当浏览器解析 import HelloWorld from './components/HelloWorld.vue' 时,会向当前域名发送一个请求获取对应的资源(ESM支持解析相对路径),浏览器直接下载对应的文件然后解析成模块记录(打开 network 面板可以看到响应数据都是 ESM 类型的 js)。然后实例化为模块分配内存,按照导入导出语句建立模块和内存的映射关系。最后运行代码。vite 会启动一个 koa 服务器拦截浏览器对 ESM 的请求,通过请求路径找到目录下对应的文件并处理成 ESM 格式返回给客户端。vite 的热加载 是在客户端和服务端之间建立了 websocket 连接,代码修改后服务端发送消息通知客户端去请求修改模块的代码,完成热更新,就是改了哪个 view 文件就重新请求那个文件,这样保证了热更新速度不受项目大小影响。开发环境会使用 EsBuild 对依赖进行个预构建缓存,第一次启动会慢一点,后面的启动会直接读取缓存

生产环境: 使用 rollup 来构建代码,提供指令可以用来优化构建过程。缺点就是开发环境和生产环境可能不一致;

1.2 Vite 生产环境为什么使用 RollUp?

1. 为什么生产环境仍然需要打包?

答: 尽管原生 ESM 现在得到了广泛支持,但由于嵌套导入会导致额外的网络往返,在生产环境中发布未打包的 ESM 仍然效率低下(即使使用 HTTP/2)。为了在生产环境中获得最佳的加载性能,最好还是将代码进行 tree-shaking、懒加载和 chunk 分割(以获得更好的缓存)。

2. 为什么使用 RollUp 作为打包工具?

答: Vite是一个由原生ESM驱动的Web开发构建工具。在选择构建工具的时候也最好可以选择基于ESM的工具。

  • 虽然 EsBuild 快得惊人,并且已经是一个在构建库方面比较出色的工具,但一些针对构建 应用 的重要功能仍然还在持续开发中 —— 特别是代码分割和 CSS 处理方面。

  • Rollup是基于ES2015JavaScript打包工具, Rollup 在应用打包方面更加成熟和灵活。它将小文件打包成一个大文件或者更复杂的库和应用,打包既可用于浏览器和Node.js使用。 Rollup最显著的地方就是能让打包文件体积很小。相比其他JavaScript打包工具,Rollup总能打出更小,更快的包。因为Rollup基于ES2015模块,比WebpackBrowserify使用的CommonJS模块机制更高效。

1.3 Vite 为什么基于 EsBuild 预构建依赖?

1. 为什么需要预构建?

答: 原因如下:

  1. 支持 commonJS 依赖: Vite是基于浏览器原生支持ESM的能力实现的,但要求用户的代码模块必须是ESM模块,因此必须将 commonJs的文件提前处理,转化成 ESM 模块并缓存入 node_modules/.vite

  2. 减少模块和请求数量: Vite 将有许多内部模块的 ESM 依赖关系转换为单个模块,以提高后续页面加载性能。比如说 lodash 工具库,里面有很多包通过单独的文件相互导入, 当代码中出现 import { debounce } from 'lodash-es' 会发出几百个 HTTP 请求, 这些请求会造成网络堵塞,影响页面的加载。通过预构建 lodash-es 成为一个模块,也就只需要一个 HTTP 请求了!

2. 为什么用 EsBuild 来预构建

答: EsBuild 为新一代的打包工具,提供了与 WebpackRollupParcel 等工具类似的打包能力, 但是在打包速度上比这三个快了将近 10-100 倍。

  1. EsBuild 使用 Go 语言编写, 该语言可以编译为原生代码,在编译的时候将语言转化为机器语言,在启动的时候直接执行即可,在 CPU 密集的场景下,GO 语言更有优势

  2. Go 语言天生具有多线程的优势

  3. EsBuild 对构建流程进行了优化,充分利用了 CPU 资源。

1.4 Vite 为什么基于 EsBuild 又基于 RollUp 呢?

1.5 Vite 是如何确保开发服务器和生产环境构建之间的最优输出和行为一致的呢?

参考资料


深入理解Vite核心原理

金九银十,带你复盘大厂常问的项目难点