跳转至

[ISSUE-0024] 扩展 reload 后 main.html tab 变成 newtab

相关源码src/entrypoints/background/index.ts(installListener) 配套被动机制src/utils/ext-context-guard.ts(v0.10.29)

用户感知的现象

用户在 chrome://extensions/?id=<myId> 详情页点击右上角"重新加载"按钮(🔄), 本扩展打开的 main.html / popup / settings / results tab 变成 Chrome 默认新标签页。

引用:

"每次点击刷新后,主界面变成浏览器默认页面的,如何确保不出现这个情况?" "原本是正常的,点刷新就变了,id 是没变的"

根因分析

已排除(用户明确)

  • manifest.key 不固定(不是这个原因 — 用户截图 url 显示 id 没变)
  • ❌ 硬编码 chrome-extension://<id> URL(同上)

真根因

阶段 现象
1. 用户点 chrome://extensions 的 reload 按钮 SW 进程被 kill 重启;所有 chrome-extension://*/ 页面 JS context 失效
2. ext-context-guard.ts 周期检测(5s) 还没轮到 → 旧 tab 看起来正常但 JS 已死
3. 用户在空窗期按浏览器刷新 Chrome 拒绝 fetch 处于 invalidated 状态的资源 → 替换 tab 为 newtab
4. 或:guard 触发 location.reload() 时 SW 尚未 ready 同上结果

核心缺陷src/entrypoints/background/index.ts:277installListener 只处理 reason === 'install' 拉欢迎页,对 update / chrome_update(reload 的真实 reason)没有任何动作。 SW 自己已经 ready 却不主动恢复 tab,纯靠页面侧被动 guard,留下空窗期。

修复方案

主动恢复(v0.10.34,本 issue)

background/index.ts installListenerupdate 分支:

if (reason === 'update' || reason === 'chrome_update') {
  restoreExtensionTabs().catch(...);
}

async function restoreExtensionTabs() {
  const myId = browser.runtime.id;
  const prefix = `chrome-extension://${myId}/`;
  const tabs = await browser.tabs.query({});
  for (const tab of tabs) {
    if (!tab.id || !tab.url?.startsWith(prefix)) continue;
    try { await browser.tabs.reload(tab.id); } catch {}
  }
}

与 ext-context-guard 双轨保险

触发源 时机 角色
background onInstalled('update') SW 自己 ready 那一刻 主动(v0.10.34)
页面侧 5s 周期 + window.error 5 秒内捕获到失效 被动(v0.10.29)

主动机制先到,几乎不留空窗;被动机制兜底(防止 onInstalled 偶发不触发)。

改动文件

文件 改了什么
src/entrypoints/background/index.ts installListener 加 update 分支 + restoreExtensionTabs()
package.json 0.10.33 → 0.10.34

验证方式

  1. pnpm build → 加载到 Chrome
  2. 打开 main.html tab,进入任意页面
  3. 在 chrome://extensions 点 reload 按钮
  4. 预期:main.html tab 自动刷新(SW 主动 reload),停留在 main.html
  5. 不应:变成 newtab / 显示空白

如何避免再犯

  • onInstalled 不要只处理 install —— update / chrome_update 也要主动恢复扩展自身 tab
  • SW 主动 > 页面被动 —— SW 启动那刻知道自己 ready,比页面侧周期检测早
  • 不假设 ext-context-guard 万能 —— 它是兜底,主动机制必须先做

相关问题