Webpack与Vite的区别与联系

0. 当前工程化痛点

主流webpack需要把整个项目编译好后再交给dev server,因此大型项目devserver启动时间很长,HMR也需要很长时间。
因此,Vite应运而生

Webpack

当我们使用webpack启动项目时,webpack会根据我们配置文件中的入口文件,

  1. 分析出项目项目所有依赖关系,
  2. 然后打包成一个文件(bundle.js),
  3. 交给浏览器去加载渲染。

在Webpack中,构建过程大概分为这么几个阶段初始化Init、构建Make、生成Seal

  • 初始化阶段: 修整配置参数,创建 Compiler、Compilation 等基础对象,并初始化插件及若干内置工厂、工具类,并最终根据 entry 配置,找到所有入口模块
  • 构建阶段: 从entry找到入口,调用loader编译模块,遍历 AST 找出模块依赖的模块,之后递归遍历所有依赖块,构建出 模块依赖关系图 (dependency graph)
  • 输出阶段: 根据output的配置,将模块拆解成不同的chunk对象,经过一系列优化,再将代码翻译成产物

描述得比较简单, 实际完成这些过程是比较复杂的

HMR

每次修改一个模块,webpack要遍历整个依赖图来找出所有依赖于该模块的其他模块。再进行局部的重新编译。
三个阶段:

  1. 找出过期的模块
  2. 从缓存中删除过期的模块
  3. 把新模块添加到modules中

webpack4以前是通过jsonp来拉取更新模块的,webpack4以及以后通过ws通信+ajax请求

devServer

原理是通过在内存中创建虚拟文件系统来提供开发服务器功能。它监听文件变化并通过 WebSocket 与浏览器通信,以实现HMR,提供高效的开发环境。

  1. 启动服务器;在本地启动http服务器
  2. 读入内存;把项目文件读入内存
  3. 编译构建;所有编译都在内存中完成,无需写入磁盘
  4. 请求转发;对于静态资源直接从内存中提供给客户端
  5. HMR;通过http升级websocket。

优化打包速度

  1. 禁止大图片转base64
  2. 利用webpack-bound-analyze分析
  3. CDN引入公共库,减少webpack打包量
  4. 开启缓存,以便在后续构建中重复使用之前的结果 cache: true
  5. 开启多线程,利用thread-loader

Vite

底层
基于esbuild和rollup,利用浏览器对ESM的支持

  • esbuild: 预构建。把不同模块规范统一编译为ESM
  • rollup:在build时打包成生产环境代码

ESM
ESM === ES module, 大部分浏览器都支持<script type='module'>
<script type="module">中,浏览器遇到内部的import引用时,会自动发起http请求,去加载对应的模块。

ESM 支持编译时就能确定模块的依赖关系

开发环境

  1. 预构建。
    1. 针对node_modules中的第三方依赖,由esbuild把所有模块编译为ESM。
    2. 整合模块,对于具有许多内部模块的,整合成一个模块。避免发送太多http请求。
    3. 缓存。把预构建好的ESM存到node_modules/.vite下。
  2. 冷启动devServer。
  3. 按需编译。页面需要某些模块会发送http请求,此时vite再进行编译,编译后发给浏览器。
    此时编译是对src源码的编译,包括对ts、less、esm、图片、字体的处理
    1. 利用http2.0 支持并发请求。
    2. 利用http缓存,
      1. node_modules 使用强制缓存
      2. src下源码 使用协商缓存

注意:
按需编译,编译了:
typescript、vue、jsx、css预处理语言、静态资源等。实际上都转换为了浏览器可以解析的html/js/css,但是由于SouceMap方便开发者,我们在F12网络看到的资源依然是index.ts这样的后缀。

HMR

当修改一个文件时vite精确定位到该模块,使其失活。vite重新编译该模块后再发送给浏览器。浏览器利用动态导入import()来替换。

原理:利用websocket连接浏览器,建立连接后监听文件变化。服务器向浏览器注入代码用于处理ws消息(重新请求模块、刷新页面)

重新请求模块依然走ajax请求,而不是ws;目的是为了保证ws只用于通信上。

生产环境

基于rollup打包,rollup轻量、打包更快。

为什么vite比webpack快

从几方面回答:

  1. vite基于esbuild、rollup
    1. esbuild基于Go,善于利用多核cpu
    2. rollup轻量,打包更快
  2. vite的预构建、冷启动、按需编译
  3. HMR的区别
  4. vite内置功能多,使用成本低