跳到主要内容

参考约 3 分钟

开发 Rust 侧

为什么原生模块无法热重载、重新编译的实际耗时,以及 bun run dev 的工作流。

JS 重挂载已在热重载里讲过。原生那一半没有热重载,也不可能做到:对 .node 文件的 require() 会调用 process.dlopen,而 Node 没有配套的卸载,活动状态(GPUI 的平台、GPU 设备、已打开的窗口、UI 线程以及选区注册表)都留在已加载的库里。第二次加载会在第一个库仍被加载的同时创造出独立的原生状态。

重新编译足够快,所以其实无所谓。在一台 M 系列 Mac 上改动一个文件后实测:

步骤 耗时
cargo check --lib 1.5s
cargo build --lib 4.9s
bun run build:debug (napi) ~2s
单个 vitest 截图文件 ~2s

bun run dev 把这套流程串成一个循环:它监视 packages/native/src,重新编译并重渲染截图测试。从改动 Rust 到生成新 PNG 大约 4 秒。

bun run dev                      # rebuild, re-render the showcase screenshots
bun scripts/dev.ts --shots diff  # only tests matching "diff"
bun scripts/dev.ts --app native-text   # rebuild, restart an example app

两件完全避免重新编译的事

  • 内容本身就在 props 里。修改 patch 或 source,下一帧就会显示。
  • 设计数值在 theme.metrics 里。调整行高或标题字号只是一次 React 重渲染。

参见原生文本组件。

确定性调度

测试渲染器使用 VisualTestAppContext 配合 TestDispatcher 来实现确定性调度。事件模拟走的是 GPUI 基于坐标的命中测试与派发 —— 而不是合成的 JS 事件。

详见测试。

贡献指南

详细的架构、通信流程与贡献指南见 AGENTS.md。