16 KiB
4-9 [recycle] 树域 Rust 家族化剩余架构事项与能力保留方案 v1
更新时间:2026-04-23
回收说明(2026-04-28):本文是 Rust 家族化下一阶段的早期架构拆解稿,后续已由
4-10执行清单、4-11final renderer / host thinning、4-16remaining final runtime、4-18final DOM shell hard gate 继续拆分和覆盖。本文保留为历史能力保留口径,不再作为当前活跃process入口。关联文档:
/mnt/Data1T/mnote/design/04-tree-domain/done/4-sidebar-pagetree-filetree-rust-web-rebuild-v1.md/mnt/Data1T/mnote/design/04-tree-domain/done/4-2-sidebar-pagetree-filetree-product-interaction-contract-v1.md/mnt/Data1T/mnote/design/04-tree-domain/done/4-6-tree-command-protocol-cutover-stage2-v1.md/mnt/Data1T/mnote/design/04-tree-domain/done/4-4-tree-projection-protocol-contract-v1.md/mnt/Data1T/mnote/design/04-tree-domain/done/4-7-tree-shell-ui-state-boundary-v1.md/mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md/mnt/Data1T/mnote/design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md/mnt/Data1T/mnote/ARCHITECTURE.md
1. 文档目的
这份文档只回答两个问题:
- 在当前长期方向已经固定为
Rust kernel + Rust web + Leptos island + Convex substrate的前提下,树域继续朝 Rust 家族化推进,还剩哪些真正的架构事项。 - 在
page tree / file tree从当前TypeScript + Next + React主壳向 Rust 家族执行面迁移时,哪些现有能力必须被完整保留,不能为了“换语言”而退化。
这份文档不是为了重复证明:
Convex是否还保留- 树域是否已经具备 projection contract
Page Aggregate是否应该存在
这些上位结论已经在关联文档中固定。
本文只做当前阶段最需要的补充收口:
树域已经完成 truth / projection / command 边界的第一轮收口,但主渲染壳仍主要停留在
TypeScript + Next + React。下一阶段要解决的,不再是“树是不是 kernel projection”,而是“树域主执行面怎样继续向 Rust 家族迁移,同时不丢掉现有交互能力”。
2. 当前判断
2.1 已经成立的部分
当前已经成立且不应回退的事实:
tree-first graph kernel继续是树域真相层。Convex继续承担存储、实时同步、内容与协作底座。mnote-web已经具备树域 projection / command / transport 的正式入口能力。sidebar_tree / page_tree / file_tree已经形成同一 projection family。- 树域主路径不应再回到“前端自己定义第二套树真相”。
也就是说,当前真正成立的结构是:
Rust kernel持有树语义。Convex提供 substrate。Rust web已开始承接 route / projection / command / stream。- 当前主站中的树 consumer 已经开始消费 projection family。
2.2 仍未完成的部分
当前仍未完成、且正是下一阶段主任务的部分是:
page tree / file tree / picker的主渲染壳仍主要是TypeScript + Next + React。file_tree的一部分 row 语义仍由前端 adapter 继续补齐,而不是完全由 Rust 直接输出。tree.*的长期命令面虽已冻结,但主调用路径仍未完全退出documents.*兼容入口。- 树域 realtime 仍未完全收口为 Rust Web 正式
snapshot + delta + resync主链。 - Sidebar 整体仍是超大客户端壳,树域虽然已收 truth,但执行面与宿主边界还不够薄。
因此当前正确判断不是:
- “树域 Rust 家族化已经完成”
而是:
树域已经完成“语义与协议收口”,但还没有完成“主执行面 Rust 家族化”。
3. 为什么继续 Rust 家族化有真实意义
3.1 不是语言洁癖,而是减少第二套运行时语义
如果长期保持下面这种结构:
- Rust 负责 kernel / query / command / projection
- Next/React 继续负责主树 UI、主交互壳、主状态骨架
那么树域会长期同时维护两套复杂度:
- Rust 侧的 projection / command / stream 语义
- 前端壳里的 row model / selection / focus / keyboard / DnD / fallback / adapter 语义
这会带来:
- 协议在两侧重复解释
- 调试时要同时跨 TS / Rust 两套执行面
- tree shell 的边界始终无法真正稳定
- 后续一切性能优化都要先穿过旧前端壳
因此这里的“继续 Rust 家族化”真正要减少的,不是文件后缀的种类,而是:
树域存在两套长期执行语义的状态。
3.2 对加载速度与运行成本有真实潜力
树域是高频常驻 UI,不是偶尔打开一次的边缘面板。
如果它继续作为大型 use client 组件族存在,就会长期保留这些成本:
- 客户端组件挂载
- 虚拟列表初始化
- DnD 状态机初始化
- 菜单与选择状态初始化
- 浏览器侧 row model 构建
- 兼容 fallback 与 stream 选择逻辑
这些成本不会因为“数据真相已经交给 Rust”而自动消失。
把树域主壳继续迁向 Rust 家族,真实收益主要来自:
- 进一步压低浏览器端常驻 JS
- 让 projection -> renderer 的路径更短
- 减少 hydration 与挂载层数
- 降低 Sidebar 切页与刷新时的重渲染放大
- 为后续更彻底的 server-first 壳收口创造条件
这里必须强调:
- Rust 化 不自动等于 更快
- 但在当前项目的长期方向里,Rust 家族化是“继续减轻旧前端壳”的必要手段
3.3 对协作冲突与长期维护也有真实意义
这里的“冲突”不只指 git merge 冲突,更主要是:
- projection contract 与 renderer 行为漂移
- TS adapter 与 Rust route 的边界反复变化
- 同一个交互在两侧同时维护 legality / normalization / fallback
当树域主执行面仍留在 React 壳里时:
- Rust 改协议
- 前端就要继续补 adapter
- 测试也要跨两族运行时拼接验证
继续 Rust 家族化的意义,是让下面这条链尽量收敛为一条语言家族更统一的主链:
- kernel truth
- projection
- tree command
- tree shell
- renderer
4. 下一阶段剩余架构事项
下面这些事项,才是树域继续 Rust 家族化时真正还没完成的主任务。
4.1 正式定义“树域主执行面”的完成标准
首先必须明确:
- “树域已经吃 projection” 不等于 “树域已经 Rust 家族化完成”
- “存在 Leptos scaffold / Rust tree_shell 模块” 不等于 “主路径 renderer 已迁完”
下一阶段完成标准应固定为:
- 至少一条真实默认用户流量,主树 renderer 不再依赖当前 React
PrivateTree/FileTree page tree / file tree / picker的核心交互骨架不再由 Next/React 主壳承担- TS 宿主只保留挂载、局部桥接、页面路由与极薄 compat
如果这一标准不先冻结,后续很容易再次把“有 Rust route”误当成“已经 Rust 化完成”。
4.2 把 page tree renderer 真正迁入 Rust 家族
page tree 下一阶段不是继续补前端 helper,而是把以下能力迁成 Rust 家族正式 renderer 能力:
- 行渲染
- 展开/折叠
- 当前页高亮
- hover 动作区
- 键盘导航
- 拖拽反馈
- 上下文菜单入口
这里的重点不是“把视觉样式翻译一遍”,而是:
- 把行级行为骨架从 React 组件迁走
- 让 page tree 只围绕正式 projection item 工作
- 不再由现有 TS 组件长期持有主路径交互状态机
4.3 把 file tree 从“前端 adapter 文件树”收口为“Rust 直接输出 + Rust 家族 renderer”
file_tree 是当前最关键也最容易退化的一段。
下一阶段必须同时做两件事:
- Rust 侧继续把
file_tree输出补完整。 - renderer 不再依赖当前前端在
pageRows + assets上继续拼 visible rows。
必须继续向 Rust 收口的内容包括:
index.md- 附件
mindmap文件夹- 导图子附件
- 表格、书籍、PDF 等对象提示
resource_kind / asset_kind / icon_hint
否则文件树即使换了新壳,也仍然只是:
- “页面树 + 前端附件补丁”
这不符合长期目标。
4.4 把树域交互骨架拆成可替换的正式模块
下一阶段不应继续把交互都堆在单一大组件里,而应显式收口为几类正式模块:
- row model
- selection model
- focus model
- keyboard model
- DnD state machine
- context action registry
无论这些模块最终落在:
Leptos- 或极薄 Rust/TS bridge
都必须满足两条:
- 它们不再定义结构真相
- 它们可以独立测试与演进
4.5 完成 tree command cutover Stage 2
树域继续 Rust 家族化时,命令面不能长期继续停在双轨。
下一阶段必须完成:
- 主路径默认发
tree.* documents.*退到 compat- legality / normalize / move target 等树策略继续回收给 Rust
否则会出现一个长期问题:
- UI 壳换成 Rust 家族了
- 但命令面仍主要经由旧
documents.*兼容语义运行
这样并没有完成真正的主执行面收口。
4.6 完成 Rust Web realtime contract
树域如果要继续往正式主链推进,realtime 必须从“可用”进入“单一正式合同”。
下一阶段需要补齐:
snapshotdeltaresync- cursor 漂移处理
- 局部 subtree 与 workspace scope 的统一
目标不是简单保住 fallback,而是让树域主路径不再依赖:
- 查询快照
- 本地 freshness 选择
- React 侧补偿式同步
4.7 收薄宿主边界
长期目标不是让主站彻底消失,而是让主站对树域只保留最小宿主职责:
- 页面布局挂载位
- 路由跳转
- 样式容器
- 极薄 feature flag / compat
- 与其他页面面板的最小桥接
不应继续保留在宿主中的内容:
- 树结构重建
- 主交互状态骨架
- 文件树资源行语义补丁
- 主要 keyboard / DnD / selection 逻辑
5. page tree 迁移时必须保留的能力
page tree 在迁移到 Rust 家族主执行面时,必须显式保证下面这些能力不退化。
5.1 结构与导航
必须保留:
- 稳定的层级展开/折叠
- 当前页高亮
- 祖先自动展开
- 搜索/过滤后层级仍可理解
禁止退化为:
- 纯扁平列表
- 只有打开功能、没有层级语义的按钮组
5.2 行级动作
必须保留:
- 新建子页面
- 重命名
- 移动
- 归档/恢复类上下文操作入口
- 行级 hover 动作区
要求:
- 不能为了换 renderer 把动作缩减到“点开页面 + 更多菜单”
- 不能丢失当前工作区级高频动作入口
5.3 键盘与焦点
必须保留:
- 上下移动
- 左右展开/折叠
- Enter 打开
- 稳定的 focus 行
要求:
focus不能重新混成selected- 展开与选择变化后焦点归一化必须稳定
5.4 拖拽与移动
必须保留:
- 基础拖拽排序
- 父节点切换
- 非法拖拽校验
要求:
- drop feedback 不能退化成不可预测的闪烁
- 目标父节点与位置推导必须有稳定、可测试的协议
5.5 大树体验
必须保留:
- 稳定滚动
- 大树下的可见区域性能
- 展开/折叠与切页不会出现明显回闪
这部分是迁移时的硬验收项,不是可选优化项。
6. file tree 迁移时必须保留的能力
file_tree 比 page tree 更容易因迁移而退化。
下一阶段必须把“功能保留”明确写成硬门槛。
6.1 资源层级
必须保留:
- 页面
index.md- 附件
mindmap文件夹- 导图子附件
- 表格、书籍、PDF 等资源对象语义
禁止退化为:
- 页面树下挂一个普通附件列表
- mindmap 资源被拍平成普通文件
6.2 选择能力
必须保留:
- 单选
- 多选
- Shift 范围选
- 右键选中
- 可见行变化后的选择归一化
这部分如果退化,文件树就不再是资源管理器语义,而会退回文档树换皮。
6.3 打开与操作
必须保留:
- 单击选择
- 双击打开资源
- 资源级右键菜单
- 按资源类型分支的动作入口
要求:
- 资源图标语义必须稳定
asset_kind / icon_hint不允许再次回到壳内临时猜测
6.4 拖放
必须保留:
- 内部拖放
- 外部文件拖入上传
- copy / move 区分
- 非法投放校验
要求:
- 文件树不能只保留视觉拖拽,没有正式动作协议
- 外部文件拖入必须继续是正式主路径能力
6.5 文件树特有的可见行模型
必须保留:
doc -> index -> asset-folder -> asset的可见行语义- 扁平化 rows 与深度的稳定映射
- 可见行变化后的选择、焦点、拖放范围归一化
这里允许实现换掉,但不允许语义丢掉。
7. 推荐迁移顺序
为了尽量保持体验不退化,推荐顺序如下:
- 先补齐
file_tree的 Rust 直接输出,避免迁 renderer 时还要继续背前端 adapter。 - 再把
page treerenderer 迁入 Rust 家族,因为它对象更单纯、验收面更小。 - 然后迁
file treerenderer,因为它依赖更多资源与交互语义。 - 再迁
picker轻量模式,让它复用同一套 renderer / state family。 - 最后继续削薄宿主,收掉剩余主路径 React 树壳。
原因:
page tree先迁可以先验证主行 renderer 与状态骨架。file_tree后迁可以避免一开始就在最复杂对象面上同时处理 renderer 与 contract 漂移。picker最适合作为共用 renderer 的轻量消费场景,而不是主线路的先导。
8. 迁移阶段的验收门槛
只有同时满足下面几条,才可以把树域继续 Rust 家族化的某一阶段视为成立:
- 页面树与文件树都没有因切流而减少已有能力。
page tree / file tree的关键能力有 smoke 覆盖:- 切页
- 展开/折叠
- 拖拽
- 右键菜单
- 多选与范围选
- 外部文件拖入
file_tree的对象投影不再依赖前端临时补丁维持主路径。- 主调用路径默认走正式
tree.*命令面。 - 正式 realtime 至少已经进入统一
snapshot + delta + resync合同,而不是继续主要靠补偿式 freshness 选择。 - 主站宿主不再持有树结构真相,也不再承担主要树域交互状态机。
9. 当前优先级建议
在当前总优先级下,树域继续 Rust 家族化的最近顺序建议固定为:
- 继续推进
4-6 tree command protocol cutover stage2 - 明确
file_tree直接输出的剩余缺口,并以 Rust 侧补齐 - 为
page tree / file tree迁移补正式功能保留回归矩阵 - 选择并落一条真实默认流量进入 Rust 家族 renderer
- 再逐步收掉当前主路径 React 树壳
也就是说,当前下一步不是:
- 继续在现有 React 树壳里堆更多交互补丁
而是:
在功能不退化的前提下,把树域从“Rust 持有语义、React 持有主执行面”的过渡态,推进到“Rust 家族同时持有语义与主执行面”的下一阶段。
10. 最终结论
当前树域继续往全 Rust 方向发展,是有真实意义的。
意义不在于:
- 代码库里减少一种语言
而在于:
- 收掉旧前端壳的长期主执行职责
- 减少第二套复杂运行时语义
- 为首屏与常驻交互链路继续减重
- 让
tree-first graph kernel -> Rust Web -> Rust family shell形成更一致的长期主链
但这个推进必须满足一个前提:
page tree / file tree 的功能能力不能因为迁移而退化。
因此,下一阶段的正确目标不是“尽快把组件翻译成 Rust”,而是:
先把剩余 projection / command / realtime / host 边界补齐,再以 page tree 与 file tree 的能力保留为硬约束,把树域主执行面稳步迁入 Rust 家族。