yang-xianzhu / astro-blog

🚀-基于Astro搭建的个人博客
https://yang-xianzhu.github.io/
5 stars 0 forks source link

面试官: vite跟webpack有什么不同? #19

Open yang-xianzhu opened 1 year ago

yang-xianzhu commented 1 year ago

1. Vite 是一个提倡No-bundle的构建工具,相比传统的 Webpack,能做到开发时的模块按需编译,而不用先打包再加载。

模块代码分为两部分:

所谓的No-bundle只是对于源代码(业务代码)而言,对于第三方依赖而言,Vite 还是选择 bundle(打包),并且使用速度极快的打包器 ESbuild 来完成。

为什么需要预构建?

-请求瀑布流问题: 比如说,知名的loadsh-es库本身是有 ES 版本产物的,可以在 Vite 中总结运行。但实际上,它在加载时会发出特别多的请求,导致页面加载的前几秒都处于卡顿状态。

每个import都会触发一次新的文件请求,因此在这种依赖层次深、涉及模块数量多的情况下会触发成百上千个网络请求,巨大的请求量加上Chrome对同一个域名下只能同时支持6个 HTTP 并发请求的限制,导致页面加载十分缓慢,与 Vite 主导性能优势的初衷背道而驰。不过,在进行依赖的预构建之后,lodash-es这个库的代码被打包成了一个文件,这样请求的数量就会骤然减少,页面加载也快了不少。

总结:依赖预构建主要做了两件事情:

而这两件事全部由性能优异的ESbuild(基于 golang 开发)完成,而不是传统的 Webpack/rollup,所以也不会有明显的打包性能问题,反而是 Vite 项目启动飞快的一个核心原因。

Vite1.x 使用了 rollup 来进行依赖预构建,在 2.x 版本将 rollup 换成了 ESbuild,编译速度提升了一个量级。

如何开启预构建

Vite 中有两种开启预构建的方式,分别是自动开启和手动开启。

我们会发现 Vite 的项目的根目录下的node_modules中发现.vite目录,这就是预构建产物文件存放的目录。

对于依赖的请求结果,Vite 的 Dev Server 会设置强缓存:

Cache-Control: max-age=3153600,immutable缓存过期时间被设置为一年,表示缓存过期前浏览器对预构建产物对请求不会再经过 Vite DevServer,而是直接用缓存的结果。

除了 HTTP 缓存,Vite 还设置了本地文件系统的缓存,所有的预构建产物默认缓存在node_modules/.vite目录中。如果一下 3 个地方都没有改动过,Vite 将一直使用缓存文件:

  1. package.json 的dependencies字段

  2. 各种包管理器的 lock 文件

  3. optimizeDeps配置内容

因为 Vite 中预构建中本地文件系统的产物缓存机制,而少数场景下我们不希望用本地的缓存文件,比如需要调试某个包的预构建结果,有以下方法可以清除缓存:

  1. 删除node_modules/.vite目录

  2. 在vite配置文件中,将server.force设为true。(在Vite3.0后中配置项需要将optimizeDeps.force设为true。

  3. 命令行执行npx vite --force 或者 npx vite optimize。

Vite 项目的启动可以分为两步,第一步是依赖预构建,第二步才是 Dev Server 的启动,npx vite optimize相比于其它的方案,仅仅完成了第一步的功能。