fix(web): 次级页稳定外壳与缓存预取,跨部署导航自愈(BUG-966/967)

This commit is contained in:
jesse-ux
2026-09-18 18:45:48 +08:00
parent dccedf372e
commit 9ccb65b71f
25 changed files with 1066 additions and 160 deletions
+43 -7
View File
@@ -12533,7 +12533,7 @@
## BUG-965 | 侧栏「星盘 / 星历 / 我的报告」点了不跳转,账户入口也没反应
- 状态:investigating(触发条件已由产品复现确认,修复未做
- 状态:resolved(由 BUG-967 修复
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`AppSidebar``NAV_PAGES` 链接与页脚账户入口;staging `877128ce`
@@ -12545,12 +12545,48 @@
3. 链接是真链接:三项导航是 `SidebarMenuLink``next/link``<Link href>``onClick={leaveChat}` 只做 `persistLoginSessionReturn()` 与关抽屉,**没有 `preventDefault`**。
4. 没有覆盖桌面侧栏的 `pointer-events: none``inert``inert` 只出现在移动端抽屉、时间轴折叠体、`SidebarInset``insetInert = modalOpen`,只盖正文区不盖侧栏)。
5. 次级页页脚是 `Link href="/"`(账户菜单只在 `/`),因此「在次级页点头像」应当跳回首页而不是没反应。
- 待取证据:控制台报错原文与 Network 面板是否有 404 的 `/_next/static/**`;点击时所在页面的 URL;该标签页是否在 17:12 部署之前就已打开;硬刷新(Cmd+Shift+R)后是否恢复
- 根因(按复现结论):标签页跨过部署后,客户端导航要拉的构建产物已被新镜像替换(构建 id 变了,旧 chunk / RSC 负载不再存在),路由切换静默失败;已经加载好的对话页因为代码都在内存里,照常工作。Next 16 自带的构建不匹配回退在这次没有把用户带到整页重载,具体是被哪一层吞掉(404 形状、Caddy、还是 RSC 负载不匹配的判定)需要在修复单里查证
- 修复方向:见 `docs/tasks/TASK-secondary-page-entry-20260918.md` BUG-967——客户端用编译期注入的 `NEXT_PUBLIC_GIT_COMMIT``/api/health``deployment.gitCommit` 比对,发现自己是旧版本就在下一次导航时整页重载,而不是静默失败
- 关联记录:BUG-744~746(侧栏统一为 `Link` 跳转)、BUG-926~929(会话列表单一数据源与外壳搬家)、BUG-936(首屏 bundle 未执行)
- 复发自:待确认
- 修复版本:待发布
- 根因:见 BUG-967。标签页跨过部署后,客户端导航要拉的构建产物已被新镜像替换;Next 16.3.1 自带的构建不匹配回退在自托管 + 预取缓存这条路上没有把用户带到整页重载,点击表现为静默无反应。已经加载好的对话页因为代码都在内存里,照常工作
- 修复:BUG-967 的版本比对自愈。旧标签页在下一次站内跳转走 `window.location.assign`
- 验证:见 BUG-967
- 防复发:见 BUG-967。不得再把「刷新就好」当成侧栏无响应的结案。
- 关联记录:BUG-967、BUG-204、BUG-744~746、BUG-926~929、BUG-936
- 复发自:BUG-204 同类(跨发布客户端导航),那次修的是 `deploymentId` / `?dpl=`,在 Vercel 上靠部署路由 404 触发 MPA;本仓是自托管单镜像,那条路径不成立。
- 修复版本:本轮提交
## BUG-966 | 星盘 / 星历 / 我的报告进入时矮等待块推挤成高正文
- 状态:resolved
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`chart-page-view.tsx``ephemeris-page.tsx``personal-report-center.tsx``use-chart-page.ts``SecondaryHeader`
- 用户现象:从侧栏进「星盘 / 星历 / 我的报告」有一瞬间抖动。
- 触发条件:进入这三页,尤其是同一会话里每次进入(没有首屏缓存)。
- 根因:三页各写各的等待布局——先渲染 46px 标题加一行短等待文案,数据到达后整块换成高正文。`SecondaryHeader``note` 未到时不渲染,标题区二次填充。`use-chart-page` 进页才 fetch,零缓存,每次都重放中间态。产品 2026-09-18 选定方案一:消灭中间态,不加 spinner,红线不动。
- 修复:三页共用 `SecondaryPageShell`(标题行高度固定、note 槽占位不塌、内容区撑满剩余视口,等待文案居中在该区)。星盘 / 星历 / 报告首屏进模块级缓存,同一会话再进直接用上次结果并后台静默刷新。侧栏三项在 `pointerenter` / `pointerdown` 预热数据。等待句仍是静态句(「这一张盘还没拿到。」等),没有 spinner / 骨架 / 「正在加载」。
- 验证:`frontend/tests/secondary-page-entry.test.ts`(三页 import 共享外壳、暖缓存第二次不经 null 等待、预取命中同一 inflight、CSS 内容区 min-height:0 且等待居中);既有 `chart-page-view` / `ephemeris-page` / sidebar 合同。浏览器量高度见 `docs/testing/secondary-page-entry-20260918.md`(无 Chrome)。
- 防复发:次级页进入不得再各写一套等待布局。揭幕后不得加 spinner / 骨架 / 「正在加载」。缓存必须模块级,组件 unmount 不能丢掉。
- 关联记录:BUG-716、BUG-717、BUG-745
- 复发自:无
- 修复版本:本轮提交
## BUG-967 | 跨部署旧标签页的客户端导航静默失效
- 状态:resolved
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`AppLink``app-navigation.ts``StaleBuildGuard`、侧栏 `NAV_PAGES` 与次级页账户入口、Web 镜像 `NEXT_PUBLIC_GIT_COMMIT`
- 用户现象:见 BUG-965。
- 触发条件:标签页在一次部署之前打开,部署后不刷新,点站内次级页或账户入口。
- 根因(查证 Next 16.3.1 源码,不得跳过):
1. 不匹配回退写在 `fetchServerResponse`RSC 不是 `text/x-component`、或非 2xx、或 `x-nextjs-deployment-id` / `flightResponse.b``getNavigationBuildId()` 时才 `doMpaNavigation``<Link>` 进页时已经把 `/chart` `/ephemeris` `/reports` 的 Flight 预取进内存;点击走缓存、不再 fetch,这条检查根本不跑。
2. 自托管只有当前镜像。Caddy 对 `/_next/static` 没有改写,只是 `reverse_proxy web:3000``?dpl=` 是 Vercel 按部署分流的参数,在本机被忽略。目标路由在新镜像上仍 200 返回新的 Flight,`!res.ok` 也不成立。
3. `handleHardNavError` / `useNavFailureHandler` 编译期开关 `__NEXT_APP_NAV_FAIL_HANDLING`standalone 默认关。旧 chunk 的 `ChunkLoadError` 若被 router reducer 吃掉,既有 `StaleClientRecovery`(只听 `window.error` / `unhandledrejection`)也看不见。客户端导航于是表现为点击无反应;挂起的 `useTransition` 还能让同一页的账户入口一起没反应。
- 修复:编译期 `NEXT_PUBLIC_GIT_COMMIT`Docker 构建时与 `NEXT_DEPLOYMENT_ID` 同值写入)对照 `/api/health` `.deployment.gitCommit`。页面重新可见时拉一次 health,导航前读这份快照。不一致则 `window.location.assign`,一致则继续客户端路由。health 失败不强制刷新。无轮询、无定时重载。
- 验证:合同测试——版本不一致走 `assign`,一致走传入的 `router.push` / 不 preventDefaulthealth 失败或 commit 为 `unknown` 不强制跳。真机跨部署见 `docs/testing/secondary-page-entry-20260918.md`
- 防复发:站内跨布局跳转走 `AppLink` / `navigateAppPath`,不得假定 Next 的 mismatch fallback 在自托管上会救场。不得用「每次导航都整页重载」或定时刷新糊过去。
- 关联记录:BUG-965、BUG-204
- 复发自:BUG-204
- 修复版本:本轮提交
## BUG-955 | 输入处理器 abort 与「合同未完成」同码,窗口装配失败藏了四周