JavaScript中Vite基于原生ESM的热更新执行原理

浅辰姑娘_8779

浅辰姑娘_8779

2026-03-19

482人浏览

原创

vite 的 hmr 快是因为不打包,基于浏览器原生 esm 实现按需编译与模块替换;通过 import.meta.hot 注入轻量更新逻辑,依赖静态导入关系精准传播更新,服务端推送 + 客户端原子 patch,单文件增量转换,响应仅 5–50ms。

javascript中vite基于原生esm的热更新执行原理

Vite 的热更新(HMR)之所以快,核心在于它不打包,直接利用浏览器原生 ESM 加载机制,在开发阶段让模块按需编译、按需替换,避免了传统打包工具的全量重构建。

ESM 动态导入是 HMR 的基础载体

Vite 启动时,会将每个源文件视为一个 ESM 模块,并通过 import.meta.hot 注入 HMR API。这个 API 不是 Vite 自己实现的运行时,而是由开发服务器在响应请求时,对原始源码做轻量级注入(如在文件末尾追加一段 JS),从而让模块具备“可接受更新”的能力。

  • 例如,当你写 import { foo } from './utils.js',Vite 实际返回给浏览器的是一个经处理的模块:它保留原始逻辑,同时附加了 import.meta.hot.accept() 监听逻辑
  • 浏览器加载模块时,执行到 import.meta.hot.accept 就注册了回调,一旦对应依赖模块变化,Vite 服务端会推送更新消息,客户端触发回调并重新执行该模块代码
  • 整个过程不经过 bundler,没有 AST 解析、依赖图重建或 chunk 生成,只做单文件编译(TS/JSX/SFC 等转为浏览器可执行的 JS)和模块替换

模块边界决定更新粒度与传播范围

HMR 更新不是全局刷新,而是基于 ESM 的静态导入关系进行精准传播。Vite 会分析模块的 import 和 export,构建轻量依赖图,仅通知直接受影响的模块及其祖先(需重新执行者)。

javascript-pro
javascript-pro

专注现代 ECMAScript、异步编程、性能优化和全栈的 JavaScript 专家,适用于现代开发

下载
  • 如果修改的是一个工具函数文件(无副作用、纯导出),且调用方使用了 import.meta.hot.accept('./utils.js', () => {...}),则只重载该模块,不触发父模块执行
  • 若未显式 accept,Vite 默认向上冒泡:修改子模块 → 父模块自动重加载 → 继续向上,直到遇到显式 hot.accept() 或到达入口(此时触发页面 reload)
  • 组件框架(如 Vue/React)插件会进一步封装 HMR 逻辑,比如 Vue 单文件组件会把 <script></script> 编译为模块,并在 accept 回调中调用 createHotContext 来卸载旧组件实例、挂载新实例

服务端推送与客户端 patch 是原子操作

当文件系统监听到变更,Vite 开发服务器不会立刻响应请求,而是:

  • 对变更文件执行按需编译(如将 Comp.vue 转为 JS 模块字符串)
  • 计算哪些模块需要被更新(基于已知的 import 关系 + 文件哈希比对)
  • 通过 WebSocket 主动向客户端发送 update 消息(含模块路径、新时间戳、新 hash)
  • 客户端收到后,发起 GET /@vite/client 或直接请求新模块 URL(带 timestamp query 强制绕过缓存),获取新代码
  • 执行新模块前,先调用旧模块的 hot.dispose()(如有),再执行新模块,最后触发 hot.accept() 回调完成局部更新

无打包 ≠ 无转换,但转换是隔离且增量的

Vite 的“原生 ESM”不等于直接 serve 源码。它仍需处理:

  • Syntax 转换(TS/JSX/Sass/MD 等 → 浏览器兼容 JS/CSS)
  • 路径别名解析(@/components → src/components)
  • 环境变量注入(import.meta.env 替换)
  • 但这些转换都是单文件、内存内、无缓存依赖的——改一个文件,只编译那一个,不读取其他模块内容,也不写磁盘

这套机制让 HMR 响应通常控制在 5–50ms 内,真正做到了“保存即生效”,且与框架解耦,只依赖 ESM 本身的能力。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

4706

5

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

2023.07.04

1169

3

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

2023.07.04

4644

6

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

2023.09.01

920

4

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

1836

5

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

2023.09.04

3365

4

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

2023.09.12

4353

6

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

2023.09.20

2840

5

java访问控制修饰符介绍
java访问控制修饰符介绍

java访问控制修饰符有四种,分别是public、protected、private、默认访问修饰符。详细介绍:1、public,public是最宽松的访问控制修饰符,被修饰的类、方法和变量可以被任何其他类访问,当一个类、方法或变量被声明为public时,它们可以在任何地方被访问,无论是同一个包中的类还是不同包中的类;2、protected修饰符等等。

2023.09.20

908

7

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WebStorm 官方调试文档
WebStorm 官方调试文档

共0课时 | 0人学习

React 教程
React 教程

共58课时 | 12.1万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 6.6万人学习