# Webpack 和 Vite 的区别

在当今的前端开发中,工程化已经成为主流,工程化的工具也已是我们在工程化中所必不可少的。webpack 应该是我们目前知名度最高,也是使用范围最广的,当然还有 Parcel、Rollup、Grunt 和 Glup 等。我们今天只分析 webpack 和 vite。

# webpack

随着工程化的进展和项目规模的增加,webpack 出现了一些对我们开发体验有影响的问题。

首先我们先简单介绍一下 webpack 的原理:

  1. 分析代码依赖。通过入口 JS 分析出整个项目的文件依赖情况,得到一个依赖图。
  2. 代码打包。对这个图中不同格式的文件调用不同的loader进行解析,然后打包处理后,放到内存中。
  3. 启动测试服务器。启动dev-server测试服务器,浏览器就可以通过地址访问到我们的项目了。
  4. HMR 热更新。代码如果在本地进行了修改,服务就通过WebSocket通知前端更新页面。

问题就出现在 第 2 步和第 4 步。在启动测试服务器前,需要先分析依赖图并打包。如果项目很大,这个过程则需要很长时间。而热更新也需要等几秒才能生效,极大的影响了我们的开发体验。

# Vite

为了解决 webpack 上述的痛点,Vite应运而生。

webpack 之所以需要进行打包操作:

  1. 因为浏览器能识别的文件类型有限,比如.vue文件他就不认识,无法运行。
  2. 因为浏览器不认识JS中有一些引入文件的方法(require)

不过现在部分浏览器支持了 ES6 中的 module 功能,可以识别使用 import 的引入文件语法。那这个问题就解决了,那Vite是如何解决问题 1 的呢?

Vite原理:

  1. 测试服务器启动ing。首先启动一个服务器用来监听项目文件,现在服务还没完全起来。
  2. 读取项目配置。读取 vite.config.js 并基于配置进行相应的处理。
  3. 预构建。 分析项目中的依赖关系,创建一个只记录模块依赖关系的文件(通常是一个JSON文件),并不会打包成文件。
  4. 创建中间件。利用原生 ES 模块特性,在浏览器中通过HTTP请求加载模块。创建一个中间件,拦截浏览器的请求,并根据预构建信息,动态提供代码模块。(解析路径、文件转译)
  5. 测试服务器启动ed。启动成功,浏览器请求模块时,中间件根据预构建信息返回相应模块。
  6. HMR 热更新。

那Vite是如何解决问题 1 的呢?主要是利用中间件,拦截请求,然后根据不同的文件后缀,进行不同的处理,解析成浏览器能看懂的信息。

我们以.vue文件为例:

  1. 请求 ./App.vue
  2. 读取.vue文件。中间件拦截,判断文件后缀为.vue,使用 @vue/compiler-sfc 包解析 .vue 文件。
  3. 拆分.vue文件。@vue/compiler-sfc 将 .vue 文件拆分为三个部分:template、script、style。每个部分单独处理。
    • template。 将template解析为render函数
    • script。 直接认定为JavaScript代码。
    • style。 被处理为JavaScript代码。(读取CSS代码 -> 创建style标签 -> CSS代码插入style标签 -> 将style标签插入head -> 返回这段JS)在浏览器中动态插入
  4. 返回处理后的内容给浏览器。

其他浏览器不认识的文件也是类似逻辑,这样Vite就不用在启动时,就省去了打包的步骤,而是在运行时再去解析相应的文件,启动速度变得十分快速。

下面再来看看Vite的热更新流程:

  1. 往客户端注入一个JS脚本文件。用开启动 WebSocket 通信,与服务端进行通信。
  2. 服务端监听文件变化。
  3. 重新编译更新的模块。
  4. 推送更新到浏览器。通过 WebSocket 进行推送。
  5. 浏览器接受并处理。通过 HMR API 进行处理,一般为 import.meta.hot 对象。

在热更新方便两者实现上相差不大,主要区别还是在架构和设计理念上。

最后,Vite在构建速度上时有很大优势的;在生态上,Vite 相对年轻,生态系统相对小。而 webpack 拥有庞大的生态系统和大量的插件;在配置上,Vite 的配置相对简单,采用了约定大于配置的原则。而 webpack 配置复杂,相对的对于个性化需求也就支持的更好。

总而言之,Vite 更适合轻量级的项目和快速的开发迭代,而 Webpack 更适合大型项目和复杂的构建需求。具体选择哪一个,还要看项目的具体需求和团队的偏好。