我正在参加「掘金·启航计划」
大家好,我是晚天。
Webpack 的第一次发布是在 2013 年发布,长久以来是主流的前端打包工具。Vite 的第一次发布是在 2021 年,是近两年来前端打包工具中的后起之秀,重点解决 Webpack 在开发阶段的开发痛点。截止 2022.6,Webpack 的 Github Star 数 61.2k,Vite 的 Github Star 数是 42.7k。虽然 Vite 刚刚发布 2 年,但是热度可见一斑。
下面我们来对 Webpack 和 Vite 的不同点进行比较,并且解释 Vite 之于 Webpack 性能优势来源于哪里?
Webpack
Webpack 是一个基于打包器的构建工具,同一个入口文件的代码会打包成一个 Bundle 文件。Webpack 长期来的一个痛点是对于大规模应用的应用启动和热更新速度很慢。
当文件发生变动时,整个 JavaScript Bundle 文件会被 Webpack 重新构建,这也是为什么使用 Webpack 的大规模应用在应用启动和热更新时速度很慢的原因。这给进行大规模 JavaScript 应用的开发者造成了很差的开发体验。
Webpack 如何工作?
Webpack 打包过程:
开发环境的 Webpack:
应用规模越大,启动和热更新代码越慢。及时启动了热更新,每次代码变更也需要重新生产 Bundle 文件。
Vite
Vite 是旨在提升开发者体验的下一代 JavaScript 构建工具,核心借助了浏览器的原生 ES Modules 和像 esbuild 这样的将代码编译成 native code 的打包工具。
Vite 主要有两方面组成:
Vite 的核心能力和 webpack + webpack-dev-server 相似,但是在开发者体验上有一些提升:
大型的 JavaScript 项目在开发和生产环境有比较差的性能表现,往往是因为我们使用的构建工具没有充分做到并行处理、内存优化和缓存。
核心理念:Bundless 开发环境构建
浏览器的原生 ES Modules 能力允许在不将代码打包到一起的情况下运行 JavaScript 应用。Vite的核心理念很简单,就是借助浏览器原生ESModules能力,当浏览器发出请求时,为浏览器按需提供ESModule文件,浏览器获取ESModule文件会直接执行。
应用启动
Vite 将应用中的模块分为依赖和源码两类,分别进行服务器启动时间的优化。
Vite 在浏览器请求时按需转换并以原生 ESM 方式提供源码,让浏览器接管了打包程序的部分工作。
Vite 如何工作?
Vite 通过原生 ES Modules 托管源代码,本质上是让浏览器来接管部分打包器的工作。Vite 只会在浏览器请求发生时,按需将源码转成 ES Modules 格式返回给浏览器,由浏览器加载并执行 ES Modules 文件。
热更新
在基于 Bundle 构建的构建器中,当一个文件变动时,重新构建整个 Bundle 文件是非常低效的,且随着应用规模的上升,构建速度会直线下降。
传统的构建器虽然提供了热更新的能力,但是也会存在随着应用规模上升,热更新速度显著下降的问题。
Vite 基于 ESM 按需提供源码文件,当一个文件被编辑后,Vite 只会重新编译并提供该文件。因此,无论项目规模多大,Vite 的热更新都可以保持快速更新。
此外,Vite 合理利用浏览器缓存来加速页面加载,源码模块请求根据 304 Not Modified 进行协商缓存;依赖模块请求通过 Cache-Control: max-age=31536000,immutable 进行强缓存,因此一旦缓存,不会再次请求。
生产环境仍需打包
在生产环境使用 ESM 会存在大量额外网络请求问题,因此生产环境不太试用 ESM,最好的方式还是代码进行 tree-shaking、懒加载、和 chunk 分隔等。
那么生产环境的构建为什么不直接使用 esbuild,而是使用 rollup 呢?这是因为 esbuild 在代码分隔、css 处理等方面的功能仍在开发中,rollup 在应用打包方面更加的成熟且灵活。
性能提升
Vite 依托支持原生 ESM 模块的现代浏览器,极大的降低了应用的启动和重新构建时间。Vite 本质上是一个在开发环境为浏览器按需提供文件的 Web Server,这些文件包含源码模块和在第一次运行时使用 esbuild 预构建的依赖模块。
Vite 和 Webpack 的主要不同在于开发环境下对于源码如何被托管以及支持哪种模块规范。
依赖预构建
Vite 在首次启动时,会进行依赖预构建。依赖预构建有两个目的:
缓存文件系统缓存
Vite 会将预构建的依赖缓存到 node_modules/.vite ,它根据几个源决定是否需要重新运行预构建步骤:
只有在上述其中一项发生更改时,才需要重新运行预构建。
如果处于某些原因,你想要强制 Vite 重新构建依赖,你可以用 --force 命令选项启动开发服务器,或者手动删除 node_modules/.vite 目录。
浏览器缓存
解析后的依赖请求会以 HTTP 头 max-age=31536000,immutable 强缓存,以提高开发时的页面重载性能。如果你想通过本地编辑来调试依赖项,可以:
Typescript 原生支持
Vite 天然支持引入 .ts 文件,单仅支持 .ts 文件的转译工作,并不执行任何类型检查。
Vite 使用 esbuild 将 TypeScript 转译到 JavaScript,约是 tsc 速度的 20-30 倍,同时 HMR 更新到浏览器的时间小于 50 ms。
对比
简单对 Webpack 和 Vite 进行一个对比:
WebpackVite总结
由于浏览器原生 ES Modules 的支持,当浏览器发出请求时,Vite 可以在不将源码打包为一个 Bundle 文件的情况下,将源码文件转化为 ES Modules 文件之后返回给浏览器。这样 Vite 的应用启动和热更新 HMR 时的速度都不会随着应用规模的增加而变慢。
参考资料
暂无评论内容