laoyang
a43950069d
修 React #321:loadJs 按 src 全局去重,避免 React 执行两遍 (#73)
用户 Console 决定性证据:
AntD 日期控件已挂上 5 处 ← 首屏
AntD 日期控件已挂上 1 处 ← 点开浮层编辑
react-dom.min.js:121 Error: Minified React error #321 (Invalid hook call)
at c.useContext (VM303 react.min.js:28:406)
at e (antd-with-locales.min.js:77:5889)
renderPicker @ app.js:2279 / mountAntdSingleDT @ app.js:2282
#321 = Invalid hook call,本次成因是"存在多份 React 副本"。
决定性线索是 VM 前缀:VM303 / VM320。
那是浏览器给 eval/new Function 动态执行的代码分配的脚本 ID;
普通 <script src> 显示的是文件 URL。同一个文件出现 VM 前缀
⇒ 它被动态执行了不止一次。
根因:app.js 里有两个独立 IIFE,各自一个 loadJs,都不去重。
· Semi 段 boot():**无条件** loadJs(conf.react) + loadJs(conf.dom)
· antd 段 ensure():只在 !window.React 时才加载 —— 看着谨慎,
但依赖"当前全局有没有 React",而 UMD 执行完才赋值。
时序:Semi 的 boot() 排在 requestIdleCallback 里。
用户点开任务 → fbBootAntd() → antd 开始加载 react.min.js(第一次)
→ Semi 的 idle 回调恰好触发 → 又插一遍(第二次)
→ 同一段 UMD 执行两次 → window.React 被覆盖
→ 但 antd 内部已捕获第一次的 React 引用
→ antd 的 useContext 在第二套的 dispatcher 上调用 → #321
修法:两个 loadJs 都改为按 src 全局去重,共享 window.__fbJsLoaded。
· 用全局而不是 IIFE 局部变量:两个 loadJs 在不同闭包里,互相看不见
· 不用 if (!window.React) 那种判断:UMD 执行完才赋值,
两个请求几乎同时发出时两边都还看不到 window.React,照样各插一个。
按 URL 去重是确定的,不依赖时序。
验证(复刻逻辑跑了三种时序):
antd 先 / Semi 后 → 第二个复用 ✅ 只有一份
Semi 先 / antd 后 → 第二个复用 ✅ 只有一份
不同文件 → 各自加载 ✅ 没被错误复用
2026-11-05 17:38:51 +08:00
..
2026-10-22 22:05:17 +08:00
2026-11-05 12:40:57 +08:00
2026-11-05 17:38:51 +08:00
2026-11-01 09:04:35 +08:00
2026-10-25 14:52:43 +08:00
2026-11-01 09:04:35 +08:00
2026-10-03 19:27:14 +08:00
2026-10-08 14:46:16 +08:00
2026-10-18 11:22:34 +08:00
2026-10-15 23:04:25 +08:00
2026-10-09 07:25:08 +08:00
2026-10-12 00:24:20 +08:00
2026-11-05 13:19:05 +08:00
2026-10-22 12:40:14 +08:00
2026-10-28 18:29:59 +08:00
2026-10-19 17:27:37 +08:00