web-font/backend/server/llrt_lr.ts
崮生(子虚) b385bc89bc perf(leafer-x-webfont): 脏节点集增量扫描,百万节点画布可正常运行
全量 walk O(全树) 改为事件驱动增量:
- property.change 携带 target(PropertyEvent 五参构造)→ 精确记脏节点
- child.add/remove 携带 child → 整棵子树入脏集(构造期赋值不走 setAttr)
- 订阅集与 Leafer 自家 Watcher 相同(property.change + child.*),
  渲染可靠 = 事件可靠;不再订阅 layout.end(每帧触发,百万级下
  周期性全量 walk 是持续卡顿源)
- 脏节点 >512 退化全量(模板整体替换场景全量更省)
- 全量/增量共用 collect/walkInto/commit,指纹短路保证无变化时
  update 调用归零
- 新增 provider 透传(测试/私有部署)、flushNow(跳过防抖立即提交)、
  updateCalls 计数(量化指纹短路效果)

压力测试(_prof_million.entry.ts,1M Text 节点):
- 初始全量 scan: ~580ms(一次性)
- 打字稳态(emit+flush): 0.024ms/键
- 无文字变化 flush ×100: 0.16ms,update=0
- 内存: 指纹表 O(family 数),与节点数无关

真实 leafer 验证(scripts/test-leafer-incremental.mts):
初始添加/改文字/新增子树全自动捕获,拖拽 50 次 0 请求 0 提交。

附带修复 dev 后端启动:llrt_lr.ts 改动态 import + fsReady
(createRequire 与 tsx ESM loader 模块图隔离导致 implInterface
注册到孤儿实例,mkdir undefined)。
2026-08-15 20:19:27 +08:00

36 lines
1.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* fs 适配层分发器。
*
* 按编译期 __RUNTIME__ 常量选择实现 —— tsdown define 常量折叠后未命中分支被消除:
* - LLRT 构建__RUNTIME__="llrt"require("./llrt"),内联进 bundle
* - Node 构建__RUNTIME__="node"require("./node"),内联进 bundle
* - devtsx ESM 直跑源码__RUNTIME__ 未定义):动态 import("./node")
*
* 适配器在模块顶层调用 implInterface 完成注册。
*
* 注意:
* - 构建分支必须保持**裸 require("./xxx")** 字面量——打包器靠静态分析内联适配器,
* 变量间接调用createRequire 等)无法被分析;且 native require 与 tsx ESM loader
* 模块缓存隔离双实例implInterface 会注册到另一个实例上,运行时必错。
* - 不能用 top-level await import —— tsdown 的 CJS 产物不支持。
* - dev 无全局 require走动态 import经 tsx ESM loader与 app 同模块图),
* 返回 fsReady 由 app.ts 的 main() 开头 await保证注册先于任何 fs 调用。
*/
/** 编译期常量tsdown define 注入dev 下未定义 */
declare const __RUNTIME__: string | undefined;
let fsReady: Promise<void>;
if (typeof __RUNTIME__ !== "undefined" && __RUNTIME__ === "llrt") {
require("./llrt");
fsReady = Promise.resolve();
} else if (typeof __RUNTIME__ !== "undefined") {
require("./node");
fsReady = Promise.resolve();
} else {
fsReady = import("./node").then(() => undefined);
}
export { fsReady };