소스 검색

docs: 记录真机预览问题(PDF 崩溃 + HTML 白屏 + CDN 漏刷)

Co-Authored-By: Claude Code <noreply@anthropic.com>
Huccct 3 시간 전
부모
커밋
e487a58109
2개의 변경된 파일과 211개의 추가작업 그리고 0개의 파일을 삭제
  1. 192 0
      docs/00-tracking/2026-11-13-真机预览问题-PDF崩溃与HTML白屏.md
  2. 19 0
      docs/00-tracking/操作追踪.md

+ 192 - 0
docs/00-tracking/2026-11-13-真机预览问题-PDF崩溃与HTML白屏.md

@@ -0,0 +1,192 @@
+# 真机预览问题:PDF 崩溃与 HTML 白屏(2026-11-13)
+
+| 字段 | 值 |
+|---|---|
+| 现象 | 电脑浏览器正常,**真机打开 PDF 报错、HTML 白屏/极慢** |
+| 关键线索 | 电脑「模拟手机」正常,真机异常 |
+| 结论 | **两个独立问题**:PDF 是浏览器 API 兼容性,HTML 是资源体积 |
+| 状态 | 已修复并部署 |
+
+---
+
+## 一、现象与关键观察
+
+用户实测反馈:
+
+> 「我在浏览器里面本地或者线上在电脑浏览器模拟手机查看都可以打开,
+> 但是部署之后在真正手机浏览器打开预览这个 html 就是白屏,卡顿,加载很慢」
+>
+> 「html 打不开白屏或者非常卡顿,然后 pdf 显示报错,其他没有问题」
+
+**决定性线索**:电脑模拟手机正常,真机异常。
+
+这说明问题**不在响应式布局**(视口相同),而在:
+- 浏览器**内核版本**
+- 网络条件下的**资源加载速度**
+
+---
+
+## 二、问题 1 · PDF 崩溃
+
+### 2.1 报错原文
+
+```
+PDF 加载失败:this[#e].getOrInsertComputed is not a function
+```
+
+### 2.2 根因
+
+`pdfjs-dist@6.4.299` 使用了 **`Map.prototype.getOrInsertComputed()`**:
+
+```js
+// node_modules/pdfjs-dist/build/pdf.mjs:2463
+this.callbacks.getOrInsertComputed(keyName, makeArr).push({...})
+```
+
+这是 **ES2026 阶段的提案 API**,浏览器支持情况:
+
+| 浏览器 | 支持版本 |
+|---|---|
+| Chrome / Edge | **133+** |
+| Safari | **18.4+** |
+| 其余 | 不支持 |
+
+**真机(尤其 iOS Safari、旧安卓 WebView)内核低于此版本 → 直接抛错。**
+
+### 2.3 为什么电脑测不出来
+
+| 测试方式 | 内核 | 结果 |
+|---|---|---|
+| 电脑浏览器直接打开 | 电脑的 Chrome(新) | ✅ 正常 |
+| 电脑 DevTools 模拟手机 | **仍是电脑的 Chrome**(只改视口和 UA) | ✅ 正常 |
+| **真机浏览器** | 手机的旧内核 | ❌ 报错 |
+
+**「模拟手机」只改变视口尺寸与 User-Agent,不改变 JS 引擎。**
+凡是依赖新 API 的代码,模拟器永远测不出来。
+
+### 2.4 修复
+
+降级到 `pdfjs-dist@4.10.38`(支持 Chrome 87+ / Safari 15+)。
+
+```bash
+npm install pdfjs-dist@4.10.38 --save-exact
+node scripts/copy-pdf-worker.mjs   # 重新生成 public/pdf.worker.js
+```
+
+验证:`grep -c getOrInsertComputed node_modules/pdfjs-dist/build/pdf.mjs` → **0**
+
+---
+
+## 三、问题 2 · HTML 白屏/卡顿
+
+### 3.1 根因:首屏资源体积大
+
+实测线上各资源(gzip 后传输量):
+
+| 资源 | gzip 后 |
+|---|---|
+| `pdf.worker.js` | **441 KB** |
+| `chunk-5HOQWZFN.js` | **488 KB** |
+| `chunk-2AI6D6CW.js` | **405 KB** |
+| 主包 `main-*.js` | 152 KB |
+
+首次打开预览时合计要下载 **1MB 以上**。
+
+在移动网络(4G/5G 但信号不稳)下,这个过程要几秒到十几秒,
+期间 iframe 是**纯白**的 —— 用户以为"打不开"。
+
+### 3.2 修复:增加加载态
+
+`file-preview.ts` 增加 `frameLoading` 信号:
+
+- 开始加载即显示「正在加载页面…」+ 旋转图标
+- `onFrameLoad()` 触发时隐藏
+- 15 秒超时改为显示「加载超时 + 重新加载」按钮
+
+---
+
+## 四、问题 3 · 部署脚本漏刷固定文件名资源(连带发现)
+
+### 4.1 现象
+
+修复 pdfjs 后重新部署,**线上 PDF 仍然报错**。
+
+### 4.2 根因
+
+检查线上 worker 大小:
+
+```
+本地新 worker:  1,375,838 bytes
+线上实际:       1,264,342 bytes   ← 还是旧版 6.4.299 的
+```
+
+`scripts/deploy.mjs` 的 CDN 刷新只包含两个 URL:
+
+```js
+--refresh_task.urls.1=https://ai.fmode.cn/
+--refresh_task.urls.2=https://ai.fmode.cn/index.html
+```
+
+而 `pdf.worker.js` 是**固定文件名、不带 hash**:
+
+- 带 hash 的 chunk(`main-4FGDOF4A.js`)换 hash 就换 URL,天然绕过缓存
+- **固定名资源内容变了但 URL 没变 → CDN 一直吐旧版本**
+
+### 4.3 修复
+
+部署脚本改为刷新固定名资源清单:
+
+```js
+const FIXED_NAME_ASSETS = ['/pdf.worker.js', '/favicon.ico'];
+```
+
+> 🔴 **以后新增固定文件名资源时,记得同步加进这个数组。**
+
+---
+
+## 五、本轮踩到的三个坑(供后续参考)
+
+| # | 坑 | 教训 |
+|---|---|---|
+| **1** | **「模拟手机」测不出真机兼容问题** | 涉及浏览器 API 的功能,必须真机验证。模拟器只改视口和 UA,内核不变 |
+| **2** | **依赖升级引入新语法** | 引入/升级依赖后,检查是否用了超出目标浏览器范围的 API。建议配 `browserslist` 让构建期降级 |
+| **3** | **固定文件名资源不走 CDN 刷新** | 部署时容易只刷新 `index.html`,漏掉 worker / favicon 这类固定名文件 |
+
+### 预防建议(未实施)
+
+1. **配置 `browserslist`**:项目当前没有 `.browserslistrc`,Angular 会按 `tsconfig.target`(ES2022)构建,但**不会**为第三方库的代码做降级。配一个明确的支持范围至少能让构建期发现问题。
+2. **部署后自动校验固定资源**:在 `deploy.mjs` 的探活阶段增加「本地文件大小 == 线上文件大小」的比对。
+
+---
+
+## 六、验证结果
+
+| 项 | 结果 |
+|---|---|
+| `pdfjs-dist` 版本 | 4.10.38 |
+| `getOrInsertComputed` 出现次数 | 0(源码与 worker 均已确认) |
+| `tsc --noEmit` | ✅ |
+| `ng build --configuration production` | ✅ 主包 152.63 KB (gzip) |
+| `ng test` | ✅ **1706 SUCCESS** |
+| 线上部署 | ✅ 探活通过 |
+| **线上 pdf.worker.js 大小** | ✅ **1,375,838**(与本地一致) |
+| git | ✅ `6ba2c67` 已推送 |
+
+---
+
+## 七、未验证项(如实披露)
+
+| 项 | 原因 |
+|---|---|
+| **真机实测** | 我无法操作真实手机,需要用户在真机上复验 |
+| 降级后 PDF 功能完整性 | 单测覆盖的是纯函数,PDF 渲染需人工打开验证 |
+| 降级是否影响其他 pdfjs 特性 | 4.10 与 6.4 的 API 差异未逐一比对 |
+
+**请务必用真机复验以下场景:**
+1. 打开 PDF 文件 → 应正常渲染,无 `getOrInsertComputed` 报错
+2. 打开 HTML 文件 → 应先显示「正在加载页面…」,然后正常渲染
+3. 在网络较差时重复上述操作
+
+---
+
+*本文所有数据为 2026-11-13 实测。*

+ 19 - 0
docs/00-tracking/操作追踪.md

@@ -7947,3 +7947,22 @@ URL 不会重复显示:`chat.service.ts:2349` 的 `stripLinks` 会把已提取
 | 约束遵守 | 未改任何代码、未重启容器、未提交 |
 | 关联文档 | [新容器接入优化-对齐lj-test基线](../03-interface/新容器接入优化-对齐lj-test基线-20261112.md) |
 
+## 2026-11-13 · 真机预览问题(PDF 崩溃 + HTML 白屏)
+
+| 项 | 内容 |
+|---|---|
+| 动作 | 排查并修复真机上 PDF 预览报错、HTML 预览白屏/卡顿 |
+| 原因 | 用户实测:电脑浏览器(含 DevTools 模拟手机)正常,**真机异常** |
+| 问题1 根因 | `pdfjs-dist@6.4.299` 使用 `Map.prototype.getOrInsertComputed`(ES2026 提案,仅 Chrome 133+/Safari 18.4+ 支持)→ 真机旧内核直接抛错 |
+| 问题1 修复 | 降级 `pdfjs-dist` 6.4.299 → **4.10.38**,重新生成 worker |
+| 问题2 根因 | 预览首屏需下载约 1MB(worker 441KB + 两个 chunk 各 ~450KB),移动网络下白屏数秒 |
+| 问题2 修复 | `file-preview.ts` 增加 `frameLoading` 加载态,显示「正在加载页面…」 |
+| 问题3(连带) | 部署脚本只刷新 `/` 与 `/index.html`,**固定名资源 `pdf.worker.js` 不刷新** → 修复部署后线上仍是旧 worker(1,264,342 vs 本地 1,375,838) |
+| 问题3 修复 | `deploy.mjs` 增加 `FIXED_NAME_ASSETS` 清单,一并刷新 `/pdf.worker.js`、`/favicon.ico` |
+| 关键教训 | **「模拟手机」只改视口和 UA,不改 JS 引擎** —— 凡是依赖新浏览器 API 的功能,模拟器永远测不出真机问题 |
+| 验证 | `tsc` ✅ / `ng build` ✅ / `ng test` **1706 SUCCESS** / 线上 worker 大小已确认为新版 |
+| 涉及文件 | `package.json`、`package-lock.json`、`scripts/deploy.mjs`、`src/app/components/preview/file-preview/file-preview.ts` |
+| git | `6ba2c67` 已推送 origin/master |
+| 未验证 | 真机实测(需用户复验)、降级后 PDF 功能完整性、4.10 与 6.4 的 API 差异 |
+| 关联文档 | [2026-11-13-真机预览问题-PDF崩溃与HTML白屏](2026-11-13-真机预览问题-PDF崩溃与HTML白屏.md) |
+