一次会误导验证结果的故障
Yggdrasil 在 2026 年 10 月的 Leptos 懒路由排障中发现:导航到慢分包页面,加载中后退,首页看起来已经恢复;但再点另一个页面时,地址变化,正文却不再更新。
“回到首页、透明度恢复、pending 清空”只能证明外观恢复,不能证明 WASM 和路由状态仍然存活。
以下内容整理自当时的历史实验,未在本文整理时重新复现,也不据此判断当前上游版本是否仍有问题。
最小验证场景要多走一步
当时的故障注入方式是延迟 /pkg/ 下的 WASM 请求,再在导航挂起中触发后退。
有效的验证步骤是:
- 从一个已完成水合的页面出发。
- 延迟目标懒路由的 WASM 分包请求。
- 导航到该页面,在 pending 期间后退。
- 确认原页面恢复。
- 再导航到第三个页面,同时核对 URL、正文和控制台。
- 补测不后退、直接再次 push 到第三页的情况。
最后两步能区分“视觉状态清理成功”和“路由运行时仍然可用”。
根因是数据 owner 比使用它的视图先销毁
当时定位到 leptos_router 0.8.17 的导航取消路径:旧页面的数据 owner 被移入可中止的预加载 future;新导航中止该 future 后,旧 owner 随之销毁,但旧视图仍显示并读取其中的 Memo,最终 panic。
原型修复让数据 owner 的存活时间不短于使用它的视图,并用“慢分包后退”和“慢分包中再次导航”两条路径验证。这个结论来自特定源码版本,不能简单推广为所有路由器都有同样问题。
动画播放中再次导航,避免重新截图
另一类问题发生在原生 View Transition 已 ready、正在播放动画时:先 skipTransition,再启动新过渡,会让刚进入的页面瞬间恢复为全亮,被截成下一次旧快照,然后再次淡出,视觉上像闪烁。
项目改为接力:沿用正在播放的原生过渡,直接提交新的导航。新快照是实时画面,因此无需为每次连续导航重新建一套过渡;同时避免旧页面重复播放进入动画。
这不是所有阶段都可无条件复用:截图后、ready 前仍需处理待提交导航;项目在该阶段排队,ready 后再接力。
点击失效也可能来自过渡命中测试
历史 Chromium 实测中,部分过渡阶段的点击命中落在 HTML,elementFromPoint 也返回 HTML,页头链接因此被吞。
项目针对已知的页头导航区域,按点击坐标找回实际链接。复现时要检查事件命中元素和过渡阶段,不能仅凭“点了没反应”认定链接监听器没有绑定。
防止交叉淡化中间变暗
旧页和新页使用不同的透明度曲线时,两者合计不透明度可能在中间大幅下降。项目让新旧透明度使用同一条互补曲线,位移仍使用独立的弹簧曲线。
验证时可以录屏或逐帧比较正文亮度,同时记录 startViewTransition 的阶段时间。只看动画结束截图会漏掉中间的暗帧。
来源
Yggdrasil 2026-10-27 至 2026-10-28 导航排障记录;视图过渡修复 edc36cdc;上游数据 owner 问题关联 Leptos PR #4973。PR 的当前状态应另行查询。