Skip to main content

Vite

什么是 Vite?

Vite 是新一代的前端构建工具,旨在为现代 Web 项目提供更快、更轻量的开发体验。它由两部分组成:

  1. 开发服务器(Dev Server):基于原生 ES 模块(ESM)提供丰富的内建功能,如速度极快的模块热更新(HMR)。
  2. 构建指令(Build Command):使用 Rollup 打包代码,并且它是预配置的,可以输出用于生产环境的高度优化过的静态资源。

为什么 Vite 在开发阶段那么快?(核心面试题)

传统的构建工具(如 Webpack)在启动开发服务器前,需要抓取并构建整个应用(Bundle),这在大型项目中会导致启动速度极慢。

Vite 将应用中的模块分为两类,并分别优化:

  1. 依赖(Dependencies)
    • 通常是那些在开发中不会改变的第三方代码(如 lodashreact)。
    • 预构建(Pre-bundling):Vite 使用 esbuild 在首次启动时对这些依赖进行预构建。esbuild 是使用 Go 编写的,比使用 JavaScript 编写的打包器快 10-100 倍。
    • 预构建主要解决两个问题:将 CommonJS/UMD 转换为 ESM;将多个内部模块依赖项合并为一个模块,减少 HTTP 请求数量。
  2. 源码(Source code)
    • 通常包含需要编译的非纯 JavaScript 文件(如 JSX、CSS、Vue 组件)。
    • 原生 ESM 供给:Vite 以原生 ESM 的方式直接将源码提供给浏览器,让浏览器接管了打包程序的部分工作。Vite 只需要在浏览器请求源码时,根据请求按需转换并提供对应的文件。不需要全量编译整个项目。

Vite 的 HMR(热更新)原理

在 Webpack 中,如果修改了一个文件,由于它是全量打包,HMR 可能会随着项目变大而变慢。

在 Vite 中,HMR 是在原生 ESM 的基础上执行的:

  • 当编辑一个文件时,Vite 只需要精确地使已编辑的模块与其最近的 HMR 边界之间的链失效。
  • 更新速度不受应用总体规模的影响
  • Vite 利用 HTTP 头来加速整个页面的重新加载:源码模块的请求会根据 304 Not Modified 进行协商缓存;依赖模块的请求会通过 Cache-Control: max-age=31536000,immutable 进行强缓存,一旦被缓存它们将不需要再次请求。

开发环境 vs 生产环境

  • 开发环境:使用 esbuild(预构建依赖) + 原生 ESM 提供服务。极速启动和热更新。
  • 生产环境:使用 Rollup 进行构建打包。
    • 为什么生产环境不用 esbuild? 虽然 esbuild 极快,但目前它在一些针对生产环境的重要特性上(如代码分割 chunking、CSS 处理等)还不如 Rollup 成熟。Rollup 拥有更成熟的插件生态和更优秀的 Tree-Shaking 能力,更适合生产环境的优化输出。

Vite 与 Webpack 的对比

对比维度WebpackVite
工作原理 (Dev)先打包(Bundle)全量编译,再启动 Server启动 Server,利用浏览器原生 ESM,按需编译(No Bundle)
启动速度较慢,随项目规模增大而显著变慢极快,基本不受项目规模影响(O(1) 启动)
热更新速度随着模块数量增加,更新变慢极快,局部更新,不受整体规模影响
底层实现纯 JavaScript(Node.js)核心部分使用 esbuild (Go) 和 Rollup
生态与成熟度生态极其庞大,插件丰富,适合各种复杂的老旧项目生态仍在快速增长,主要针对现代浏览器和现代前端框架
适用场景需要兼容老旧浏览器、有复杂构建逻辑的大型/传统项目追求极致开发体验的现代 Web 项目

常见的面试题补充

1. Vite 如何处理 CSS 和预处理器? Vite 提供了对 .css, .scss, .less 等文件的内置支持。在开发环境中,CSS 会被注入到页面的 <style> 标签中;在生产环境中,CSS 会被提取为单独的文件并进行压缩。

2. 既然 Vite 依赖 ESM,那如何兼容老旧浏览器? Vite 官方提供了一个插件 @vitejs/plugin-legacy,它会自动生成传统版本的 chunk 以及相应的 ES 语法 Polyfill,并在不支持原生 ESM 的浏览器中通过 <script nomodule> 的方式加载。