六维教程

Vite 的核心原理

上一篇我们建立了直观印象,Vite 很快,因为它不在开发阶段全量打包。这一篇我们把原理拆开看,搞清楚它在开发环境和生产环境分别用了什么策略,以及它和 Webpack 的本质区别在哪里。

开发环境基于原生 ESM

现代浏览器(Chrome、Edge、Firefox、Safari 的新版本)都原生支持 ES Module。也就是说,浏览器本身就能通过 importexport 语法加载模块,不需要任何打包器介入。

Vite 在开发时做的事情非常简单,它启动一个服务器,当你在浏览器打开页面,浏览器发请求要某个模块,Vite 就实时把那个模块编译成浏览器能懂的 ESM 格式返回。

// main.js
import { createApp } from 'vue'
import './style.css'

createApp().mount('#app')

浏览器看到 import,就会自己再去请求 vuestyle.css。Vite 只负责在收到请求时,把对应的文件转译好再返回,整个过程没有「先打包再运行」这一步。

按需编译带来毫秒级启动

传统工具启动时要分析整个依赖图,Vite 不需要。它只在浏览器真正请求某个文件时才去编译那个文件。

这就带来一个关键结论,Vite 的启动时间和项目规模基本脱钩。无论你的项目有 10 个文件还是 1000 个文件,Vite 启动时要做的只是「起一个服务器」,所以几乎是秒开。

只有当你在浏览器里访问到某个页面、请求了某个模块,那个模块才会被编译。这种「用到才编译」的策略,叫做按需编译(on-demand compilation)。

依赖预构建解决两个问题

源码模块可以按需编译,但第三方依赖(比如 Vue、React、lodash)不能直接这么干,原因有两个。

第一,很多库发布的是 CommonJS 或 UMD 格式,浏览器原生 ESM 不认识,必须转成 ESM。

第二,有些库一个包里引用了成百上千个小文件,如果浏览器逐个请求,会产生大量网络请求,反而变慢。

所以 Vite 在启动时会对依赖做一次预构建(Pre-bundling),它用 esbuild 这个用 Go 语言写的极速工具,把依赖打包成少数几个 ESM 文件,并缓存起来。esbuild 比传统的 JS 打包器快一个数量级,所以预构建本身也很快。

预构建的结果会被缓存到 node_modules/.vite 目录,只要依赖没变,下次启动直接复用,不会重复构建。

模块热替换让修改即时可见

HMR(Hot Module Replacement,模块热替换)指的是,你修改某个模块后,浏览器只更新那个模块,而不用刷新整个页面。

传统工具的 HMR 往往要重新构建整条依赖链,Vite 则借助 ESM 的天然优势,只把改动的那一个模块重新发送给浏览器,由浏览器局部替换。这样既保留了页面状态(比如表单输入不会丢失),速度也快得多。

生产环境使用 Rollup 打包

开发时讲究「快」,生产时讲究「小」和「稳」。因此在构建上线版本时,Vite 切换策略,使用 Rollup(以及正在演进、由 Rust 实现的 Rolldown)来做完整的打包优化。

为什么要换工具?因为浏览器原生 ESM 不适合直接上线。

  • 如果每个模块都单独发请求,用户访问页面会发起成百上千个请求,加载很慢。
  • 没有经过压缩、Tree Shaking、代码分割等优化,体积降不下来。

Rollup 擅长把代码打包成少量、高度优化的静态文件,并自动剔除没用到的代码。Rolldown 是 Vite 官方正在推进的下一代打包器,用 Rust 重写,速度更快,目前可以通过 rolldown-vite 这个包提前体验,未来会成为 Vite 的默认打包核心。在日常使用中,你不需要关心具体是哪个,Vite 已经替你选好了。

Vite 与 Webpack 的核心差异

对比项 传统工具(Webpack) Vite
开发启动 先全量打包,项目越大越慢 起服务器即可,与规模脱钩
模块加载 浏览器加载打包产物 浏览器原生 ESM 按需加载
热更新 重建依赖链,较慢 单模块替换,极快
依赖处理 一起打包 esbuild 预构建并缓存
生产构建 自身打包 Rollup / Rolldown 打包

一句话总结,Vite 把「开发时」和「生产时」拆成两套策略,开发时靠浏览器原生能力求快,生产时靠成熟打包器求优。

本篇小结

  • 开发环境基于原生 ESM,按需编译,启动几乎瞬时。
  • 依赖预构建用 esbuild 解决格式转换和请求过多的问题。
  • HMR 做到单模块热替换,改代码不刷新整页。
  • 生产环境用 Rollup(未来 Rolldown)做优化打包。

下一篇我们动手创建第一个 Vite 项目,把原理变成可以运行的代码。

上一篇
Vite 为什么需要 Vite
下一篇
Vite 搭建第一个项目