Vite快的核心在于开发时利用浏览器原生ESM按需加载,不全量打包;依赖预构建用esbuild转译CJS/UMD为ESM并缓存;开发与生产分双阶段,前者只做拦截编译,后者交由Rollup完整打包优化。

掌握 Vite 构建核心,关键不在死记配置项,而在于理解它“为什么快”以及“怎么工作”的底层逻辑。复习时抓住三个支点:浏览器原生 ESM 的利用方式、依赖预构建的必要性、开发与生产双阶段的不同角色。下面分四块帮你理清脉络。
搞懂开发阶段不打包是怎么实现的
Vite 开发服务器启动后,并不把整个项目打包成一个 bundle,而是靠浏览器自己解析 <script type="module">。你写的 import { createApp } from 'vue',浏览器会直接发 HTTP 请求去加载 /src/main.js;接着又根据 import 自动请求 /src/App.vue、/@modules/vue 等路径。
Vite 做的是拦截这些请求,做三件事:
- 对源码中的裸模块(如
'vue')重写为'/@modules/vue',让路径合法可请求 - 拦截
/@modules/xxx请求,从node_modules中找到对应包的package.json,读取module字段定位 ESM 入口文件 - 读取该入口内容,再递归重写其中的裸模块引用,确保整条链路都符合 ESM 规范
理解依赖预构建到底在解决什么问题
不是所有 npm 包都天然支持 ESM。很多库仍用 CommonJS(module.exports)或 UMD 格式发布。浏览器无法直接执行它们,Vite 就必须提前处理。
预构建发生在首次启动 dev server 时,本质是用 esbuild 把这些非 ESM 依赖转成浏览器能跑的 ESM 形式,并缓存到 node_modules/.vite 目录下:
- 缓存依据包括
package-lock.json、vite.config.js中optimizeDeps配置、以及依赖内容哈希 - 后续启动若依赖没变,就跳过预构建,直接复用缓存,冷启动极快
- 如果代码里新引入了一个没预构建过的包(比如动态
import('some-unknown-lib')),Vite 会自动触发二次预构建并热更新页面
分清开发和生产两个阶段的核心任务
Vite 不是一个“全场景统一方案”,它明确划分了职责:
- 开发阶段:只 serve 源码 + 按需编译 + HMR,完全跳过打包。目标是快启动、快响应、真热更
- 生产阶段:调用 Rollup(默认)进行完整打包,做 tree-shaking、代码分割、CSS 提取、资源哈希等优化,输出静态文件
这意味着:vite build 和 vite dev 走的是两套完全不同流程,不能拿开发行为去类推构建结果。
动手验证比看文档更有效
光读原理容易飘,建议用最小项目实操验证:
- 新建空项目,装
vue和lodash-es,在main.js中分别import { debounce } from 'lodash-es'和import _ from 'lodash' - 启动
vite dev,打开浏览器 Network 面板,观察请求路径:前者走/@modules/lodash-es,后者会触发预构建并生成/@modules/lodash缓存 - 删掉
node_modules/.vite,重启服务,看控制台是否打印 “Pre-bundling dependencies…” - 改一行
App.vue,注意控制台 HMR 日志和浏览器 DOM 是否局部更新,而非整页刷新
真正吃透 Vite,就是把“浏览器请求 → Vite 拦截 → 路径重写 → 文件读取 → 再次重写 → 返回 ESM”这条链路,在脑子里跑通几遍。


















