Files
cc-web/.trellis/tasks/08-07-fix-title-anchor/research/root-cause.md
2026-08-07 14:22:52 +08:00

1.7 KiB
Raw Blame History

标题位置回归根因

结论

标题锚点实现没有再次丢失。截图来自仍运行旧版 app.js 的长期打开标签页; cc-web 当前没有前端资源版本握手,服务重启只会让 WebSocket 重连,不会替换 浏览器内存中已经执行的旧 JavaScript。

证据

  1. server.js 生成的标题事件包含 anchorMessageIndex,当前会话实证为 messageIndex: 1、anchorMessageIndex: 0。
  2. public/app.js 优先按显式锚点排序,标题位置为 anchorMessageIndex * 2 - 1,锚点消息位置为 anchorMessageIndex * 2。
  3. 18 条持久化事件中 15 条有合法锚点;3 条旧事件均可由既有兼容回退找到 事件前最近的用户消息。
  4. PM2 没有覆盖 CC_WEB_PUBLIC_DIR;8002 端口返回的脚本与仓库 public/app.js SHA-256 一致,并包含标题锚点代码。
  5. 静态响应为 Cache-Control: no-store, max-age=0,刷新页面即可获得新脚本; 但已打开标签页不会因为磁盘或服务端代码更新而自动替换内存脚本。
  6. title-history-outline 专项回归通过,CSS 也没有二次改变标题与消息的 DOM 顺序。

方案

  • 服务端根据当前 app.js 内容生成短 SHA-256 指纹。
  • 返回 index.html 时把指纹注入脚本 URL,使客户端能记录实际加载版本。
  • WebSocket 鉴权成功消息下发同一指纹。
  • 客户端仅在两端指纹都存在且不一致时刷新,并用会话内标记防止重复刷新。

边界

  • 首次部署该机制前已经打开的旧标签页没有自检代码,仍需刷新一次;之后的版本 变更可在服务重启、WebSocket 重连时自动收敛。
  • 不改写已正确的标题锚点算法和历史会话数据。