10.3 热重载
> **本节目标**:理解 RML 的热重载机制,掌握开发期的实时迭代工作流。
10.3.1 热重载的价值
传统 GPUI 开发中,每次改 UI 都要重新编译运行,耗时数十秒。RML 的热重载让 `.rml` 模板的修改在**秒级**内反映到运行中的窗口,极大缩短反馈循环。
| 改动类型 | 是否可热重载 | | ----------- | ---------------- | | `.rml` 模板 | ✅ 完全热重载 | | 样式表 | ✅ 完全热重载 | | ViewModel 字段 | ❌ 需重新编译 | | 命令 / 计算属性 | ❌ 需重新编译 | | Model 结构 | ❌ 需重新编译 |
热重载覆盖“UI 调试”这一最高频场景,业务逻辑变更仍需重新编译。
10.3.2 工作原理
┌──────────────────────────────────────────────────────────┐
│ RML 热重载流程 │
│ │
│ 文件监听器 ──▶ 增量解析 ──▶ 语义验证 ──▶ 重新生成渲染代码 │
│ │ │
│ ▼ │
│ 运行时热重绘 ◀── 通过 IPC 通知应用 ◀── 输出到内存缓冲 │
│ │ │
│ ▼ │
│ 替换当前视图的 Render 实现,保留 ViewModel 状态 │
└──────────────────────────────────────────────────────────┘
关键点:
1. **文件监听**:watch `src/**/*.rml` 与 `**/*.rmlcss` 2. **增量编译**:只重编译变化的文件,不重新跑全量 build 3. **状态保留**:ViewModel 状态不丢失,UI 平滑过渡 4. **IPC 通知**:编译进程通过本地 socket 通知运行中的应用
10.3.3 启用热重载
Cargo.toml
[dependencies]
rml = { version = "0.1", features = ["hot-reload"] }
[profile.dev]
# 热重载只在 dev profile 下启用
main.rs
fn main() {
rml::init_hot_reload(); // 启动文件监听
Application::new().run(|cx| {
cx.open_view::<AppView>();
});
}
运行
cargo run
应用启动后,修改任何 `.rml` 文件并保存,窗口立即更新。
10.3.4 热重载的边界
可热重载的改动
- 增删改元素 - 修改属性、class、style - 修改 `if` / `each` 条件 - 修改 `value={field}` 绑定路径(前提:路径在 ViewModel 中存在) - 修改插值表达式 - 修改样式表内容
不可热重载的改动
- ViewModel 新增 / 删除字段 → 重新编译 - 修改命令方法签名 → 重新编译 - 修改 Model 结构 → 重新编译 - 修改 `value={field}` 指向不存在的字段 → 热重载失败,提示错误
部分热重载失败的处理
当热重载遇到错误(如绑定路径不存在)时:
- 应用**不崩溃**,保持上一个有效状态 - 在窗口角落显示错误提示 - 终端打印错误详情 - 修复后保存,自动重试
10.3.5 热重载与状态保留
热重载的核心价值是**保留 ViewModel 状态**。例如调试一个表单时,已填写的字段在改模板后依然存在。
状态保留的机制
热重载时:
1. 旧 View 被销毁,但 ViewModel 的 `Entity` 被保留 2. 新 View 用同一 ViewModel 重新构建 3. 绑定重新建立,UI 反映当前状态
状态丢失的场景
- ViewModel 字段类型变化(如 `String` → `u32`):旧值无法迁移,重置为默认 - 重新编译运行:所有状态归零 - 视图被关闭重开:ViewModel 重建
10.3.6 热重载的最佳实践
1. 用 mock 数据填充状态
调试 UI 时,先在 `#[on_loaded]` 中填入典型数据,这样热重载后能立即看到有内容的界面:
#[on_loaded]
pub fn on_loaded(&mut self, cx: &mut ViewContext<Self>) {
#[cfg(debug_assertions)]
{
self.items = mock_items();
self.user = mock_user();
cx.notify();
}
}
2. 频繁保存
热重载在保存时触发。养成“改一点存一下”的习惯,实时看效果。
3. 配合 Inspector
热重载 + Inspector 是最强调试组合:改模板 → 看 Inspector → 再改 → 再看。
4. 隔离复杂视图
把大视图拆成小组件,每个组件可独立热重载,避免一处改动触发全量重编译。
10.3.7 热重载的性能
| 文件规模 | 增量编译耗时 | | ----------- | --------- | | 单文件小改动 | < 100ms | | 单文件大改动 | 100-500ms | | 跨文件样式变更 | 200ms-1s | | 全量重编译(不可热重载) | 5-30s |
热重载比全量编译快 10-100 倍,是开发期的主要反馈手段。
10.3.8 排查热重载问题
热重载不生效
1. 检查 `rml` 是否启用 `hot-reload` feature 2. 检查是否在 `dev` profile 3. 检查文件是否在被监听的目录内 4. 检查 IDE 是否真的写盘(某些 IDE 缓存写入)
热重载后状态丢失
1. 检查是否触发了全量重编译(看终端日志) 2. 检查 ViewModel 字段类型是否变化 3. 检查视图是否被关闭重开
热重载报错
1. 看终端输出的错误详情 2. 用 `rml-expand` 看生成代码 3. 修复后保存,自动重试
下一节 → [10.4 构建流程](./build-pipeline.md)