Vite

概述

Vite是新一代的前端构建工具,类似于 Webpack+ Webpack-dev-server。
在开发环境利用浏览器的 ESM,完全跳过打包环节,按需加载;生产环境则利用 Rollup 打包。

特点:

  • 快速冷启动,No Bundle + esbuild
  • 模块热更新,基于 ESM 的 HMR,同时利用浏览器缓存
  • 按需加载,基于 ESM

ESM

ESM 是 JavaScript 提出的官方标准化模块系统,作为 ECMA 标准,已经有绝大部分浏览器支持。

ESM的执行可以分为三个步骤:

  • 构建,查找模块
  • 实例化,创建实例
  • 运行,内存关联实例

从上面实例化的过程可以看出,ESM 使用实时绑定的模式,导出和导入的模块都指向相同的内存地址,也就是值引用。而 CommonJS 采用的是值拷贝,即所有导出值都是拷贝值。

Esbuild

Vite底层使用Esbuild实现对 .ts、.jsx、.js 代码文件的转化。

Esbuild 是由 Figma 的 CTO 「Evan Wallace」基于 Golang 开发的一款打包工具,相比传统的打包工具,主打性能优势,在构建速度上可以快10~100 倍。

它的优势来源于 GO 语言的能力:

  • 编译运行 vs 解释运行
  • 多线程 vs 单线程

目前他支持以下的功能:

  • 加载器
  • 压缩
  • 打包
  • Tree Shaking
  • Source Map

Esbuild总共提供了四个函数:transform、build、buildSync、Service。有兴趣的可以移步官方文档了解。

Rollup

在生产环境下,Vite 使用 Rollup 来进行打包。

Rollup是基于ESM的JavaScript打包工具。
能针对源码进行 Tree Shaking。
Scope Hoisting 减小输出文件大小。

核心原理

ES6 的模块加载:

1
<script type="module" src="/src/main.js"></script>

当声明一个模块时,浏览器会解析地址并在当前域名发起一个 GET 请求 main.js 文件。并在文件内部递归发起 import 的文件请求。

Vite核心原理:

  • 利用 ES6 的 import, 遇到 import 就发送一个 HTTP 请求加载文件
  • Vite 启动一个 Koa 服务拦截发送的请求,在Koa服务中对文件进行简单的分解 与 整合
  • 以 ESM 格式返回给浏览器

按需加载

只加载当前页面用到的模块,而且不需要解析依赖、打包 等过程。

热更新

webpack:通过 WebSocket 建立浏览器和服务器的连接,监听到文件变化,则重新加载模块。

Vite:

  • 创建 WebSocket
  • chokidar 监听文件变更
  • 通知变更
  • 获取更新文件

利用浏览器的缓存

因为是利用 HTTP 发起的文件请求,所以可以利用浏览器的缓存机制。

基于esbuild的预编译

Vite预编译之后,将文件缓存在 node_modules/.vite/

预编译的作用:

  • 支持CommonJS,转化成 ESM 模块并缓存入 node_modules/.vite
  • 减少请求数量
    例如:lodash-es 这种包会有几百个子模块,当代码中出现 import { debounce } from ‘lodash-es’ 会发出几百个 HTTP 请求, Vite 将有许多内部模块的 ESM 依赖关系转换为单个模块,以提高后续页面加载性能。