在使用 Bun 全栈开发服务器时,HMR 默认启用。
import.meta.hot API 参考
Bun 实现了一个客户端 HMR API,参考了 Vite 的 import.meta.hot API。可以用 if (import.meta.hot) 来检测,生产环境中会被 tree-shaking 去除。
HMR API 仍在开发中,一些功能尚未实现。在
Bun.serve 中可以通过设置 development 选项 { hmr: false } 来禁用 HMR。API 方法
| 方法 | 状态 | 说明 |
|---|---|---|
hot.accept() | ✅ | 表示模块支持热更新可以安全替换。 |
hot.data | ✅ | 在模块更新间保持数据状态。 |
hot.dispose() | ✅ | 添加模块即将替换时执行的回调函数。 |
hot.invalidate() | ❌ | |
hot.on() | ✅ | 绑定事件监听器。 |
hot.off() | ✅ | 移除通过 on 绑定的事件监听器。 |
hot.send() | ❌ | |
hot.prune() | 🚧 | 注意:回调目前从未被调用。 |
hot.decline() | ✅ | 无操作函数,匹配 Vite 的 import.meta.hot。 |
import.meta.hot.accept()
accept() 方法表示模块可以被热替换。无参数调用时,表示该模块可简单通过重新执行文件来替换。热更新后,该模块的所有导入者会自动被更新补丁。
index.ts 引入的所有文件创建了一个热重载边界。也就是说,只要 foo.ts 或其任何依赖被保存修改,更新会冒泡到 index.ts 并重新执行。导入 index.ts 的文件随后会被更新补丁,导入新版本的 getNegativeCount()。如果只有 index.ts 被更新,只有该文件重新执行,且 foo.ts 里的计数器会重用。
这可以与 import.meta.hot.data 结合使用,将状态从旧模块传递到新模块。
当没有任何模块调用
import.meta.hot.accept()(也没有 React Fast Refresh 或插件调用它),
文件更新时页面会刷新,且控制台会显示哪些文件被失效。若你更倾向于使用页面刷新,这个警告可忽略。带回调
如果传入一个回调,import.meta.hot.accept 将像 Vite 那样工作。它不会自动补丁导入者,而是把新模块作为参数调用回调。
接受其它模块
多依赖
undefined。
import.meta.hot.data
import.meta.hot.data 用于在热替换期间在模块实例间持久状态,从前一个模块传递数据到新模块。当写入 import.meta.hot.data 时,Bun 会同时标记该模块为自接受(相当于调用了 import.meta.hot.accept())。
data 会被内联为 {},因此不能用作状态持有。
import.meta.hot.dispose()
绑定一个销毁回调。该回调在以下时被调用:- 模块即将被替换(即新模块加载前)
- 模块被卸载(所有对该模块的导入被移除,见
import.meta.hot.prune())
import.meta.hot.prune()
绑定一个清理回调。在所有导入这个模块的引用被移除之后调用,但该模块之前已经加载过。 这可以用来清理模块加载时创建的资源。相比于import.meta.hot.dispose(),这个方法更适合与 accept 和 data 配合管理有状态资源。以下是一个管理 WebSocket 的完整示例:
若使用
dispose,WebSocket 会在每次热更新时关闭并重新打开。两种写法都能避免导入文件更新时页面刷新。import.meta.hot.on() 和 off()
on() 和 off() 用于监听 HMR 运行时事件。事件名称带有前缀,避免插件间冲突。
内置事件
| 事件 | 触发时机 |
|---|---|
bun:beforeUpdate | 在热更新应用之前 |
bun:afterUpdate | 在热更新应用之后 |
bun:beforeFullReload | 在页面完全刷新前 |
bun:beforePrune | 在调用 prune 回调前 |
bun:invalidate | 当调用 import.meta.hot.invalidate() 使模块失效时 |
bun:error | 当构建或运行时发生错误 |
bun:ws:disconnect | HMR WebSocket 连接断开时,表示开发服务器可能离线 |
bun:ws:connect | HMR WebSocket 连接或重新连接时 |
为兼容 Vite,以上事件也可用带
vite:* 前缀替代 bun:*。