webpack与vite
# webpack与vite
在浏览器没有原生模块化支持的时代,我们往往需要通过
webpack等构建工具将整个项目打包成一个js文件,方便浏览器进行调用。但是随着浏览器厂商的不断努力,现代浏览器基本已经全部支持了import/ export语法,于是Vite就出现了。
Vite 是一个由原生 ESM 驱动的 Web 开发构建工具。在开发环境下基于浏览器原生 ES imports 开发,在生产环境下基于 Rollup 打包。
Vite默认的构建目标浏览器是能 在script标签上支持原生ESM和 原生ESM动态导入。传统浏览器可以通过官方插件支持。
webpack官方文档 (opens new window)
# 差异
webpack 的本质就是先打包,再加载;Vite 在开发环境下,模块以原生
esm的形式被浏览器加载, 生产环境下,模块被Rollup以传统方式打包。Webpack 会先打包,然后启动开发服务器,请求服务器时直接给予打包结果;而 Vite 是直接启动开发服务器,请求哪个模块再对该模块进行实时编译。
由于 Vite 在启动的时候不需要打包,也就意味着不需要分析模块的依赖、不需要编译。因此启动速度非常快。当浏览器请求某个模块时,再根据需要对模块内容进行编译。
- 从定位来说两者就是不一样的:
webpack core是一个纯打包工具(对标Rollup); 而Vite其实是一个更上层的工具链方案,对标的是(webpack + 针对 web 的常用配置 + webpack-dev-server)。
webpack core因为只针对打包不预设场景,所以设计得极其灵活,不局限于针对web打包,几乎所有可配置的环节都做成了可配置的。这种极度的灵活性对于一些特定场景依然不可替代。但反过来导致的缺点就是配置项极度复杂,插件机制和内部逻辑晦涩难懂,针对常见的web也需要大量的配置。
Vite的选择是缩窄预设场景来降低复杂度。如果预设了web的场景,那么大部分常见的web构建需求都可以直接做成默认内置;所以在纯web这个目标场景下,Vite可以做到在对标webpack栈对等功能的前提下极大的降低配置复杂度和提升开发体验
Vite支持开箱即用的引入.ts文件,.jsx与.tsx也是开箱即用,也为Vue提供第一优先级的支持; 而webpack则需要引入各种loader将文件编译为.js文件。从打包成品来看:
webpack是包了一大堆iife闭包,Vite用Rollup打包,rollup则简洁得多,基本上是把不同的源文件的变量改名然后依然放在同一顶层作用域下。这个设计本身也要比webpack简洁合理且节省空间时间;webpack开发环境下webpack dev server也打包,浪费了现代浏览器的esm支持能力,这一点是vite的核心优势。Webpack生态比较完善,可以找到各种满足场景的插件;Vite由于刚出来没多久,目前生态还不够完善;
# vite快的原因
# Vite改进了开发服务器启动时间
- webpack 需要对所有运行资源进行提前编译处理,对依赖模块进行了语法分析转义,最终将模块被打包到内存中;
当我们开始构建越来越大型的应用时,使用 JavaScript 开发的工具通常需要很长时间才能启动开发服务器,即使使用 HMR,文件修改后的效果也需要几秒钟才能在浏览器中反映出来。
- Vite 通过在一开始将应用中的模块区分为 依赖 和 源码 两类,改进了开发服务器启动时间。
Vite 在第一次加载的时候会使用
esbuild预构建依赖 (opens new window)。预构建可以提高页面加载速度,并将 CommonJS / UMD 转换为 ESM 格式。预构建这一步由 esbuild 执行,这使得 Vite 的冷启动时间比任何基于 JavaScript 的打包器都要快得多。Esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。
通过依赖预构建,Vite 将有许多内部模块的 ESM 依赖关系转换为单个模块,以提高后续页面加载性能。
Vite以原生ESM方式提供源码,这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。在Vite中,启动服务器时,是不需要提交编译文件,而是在浏览器请求对应URL时,再提供文件,实施了真正的路由懒加载,这个比起Webpack就要节省了不少时间。
# Vite减少了热更新时间
webpack虽然支持动态模块热重载(HMR),即允许一个模块 “热替换” 它自己,而不会影响页面其余部分,但实践证明,其热更新速度也会随着应用规模的增长而显著下降。- 在
Vite中,HMR是在原生ESM上执行的。当改动了一个模块后,仅需让浏览器重新请求该模块即可,不像webpack那样需要把该模块的相关依赖模块全部编译一次,效率更高。使得无论应用大小如何,HMR 始终能保持快速更新。
Vite同时利用HTTP头来加速整个页面的重新加载(再次让浏览器为我们做更多事情):源码模块的请求会根据304 Not Modified进行协商缓存,而依赖模块请求则会通过Cache-Control: max-age=31536000,immutable进行强缓存,因此一旦被缓存它们将不需要再次请求。