Skip to content

[提案] 将安装后的返回操作改为由标签页侧上下文执行 #1588

Description

@cyfung1031

涉及模块

  • src/app/service/service_worker/script.ts
  • 用户脚本安装入口的标签页导航流程
  • 安装页打开后的原标签页回退行为

当前实现

ScriptService.listenerScriptInstall() 会监听受支持的用户脚本安装入口,并调用 openInstallPageByUrl() 打开 ScriptCat 安装页。

安装页交接结束后,当前代码在 finally 中调用 chrome.scripting.executeScript(),向 req.tabId 对应的标签页注入并执行:

history.back();

该调用的实际目的不是执行通用页面脚本,而只是让被拦截的标签页返回上一条历史记录。

本 issue 仅处理这一处安装后回退逻辑,不涉及 ExecScript、用户脚本运行时或项目中其他合理的脚本注入场景。

问题说明

当前实现能够表达所需行为,但所用 API 与实际意图并不完全匹配:

  • scripting.executeScript() 的语义是向目标页面注入并运行 JavaScript;
  • 本处真正需要表达的是“让指定标签页返回上一条历史记录”;
  • 该操作不需要访问页面 DOM,也不需要在页面上下文中执行任意代码;
  • 使用脚本注入会额外依赖目标页面类型、注入权限、执行时机和页面执行环境。

因此,本 issue 的核心不是“Firefox 禁止了 scripting.executeScript()”,而是移除一个没有必要通过动态代码注入完成的固定标签页导航操作。

更直接的实现可以让代码语义与业务目的保持一致,同时减少权限、上下文和浏览器差异带来的不确定性。

与 Firefox / Mozilla Bug 2015559 的关系

需要避免以下不准确表述:

Firefox 不允许扩展使用 scripting.executeScript()

Firefox 仍支持 scripting.executeScript()。Mozilla Bug 2015559 针对的是向 moz-extension: 扩展文档注入内容脚本、JavaScript 或 CSS,并不是全面禁用该 API,也不能据此认定 ScriptCat 当前所有安装入口都会被阻塞。

ScriptCat 当前流程可能涉及:

  • 普通 HTTP/HTTPS 页面;
  • file: 页面;
  • 经 declarativeNetRequest 重定向后的扩展安装页。

不同入口和执行时机下,req.tabId 对应标签页的最终页面类型可能不同。即使部分路径不受 Bug 2015559 影响,本处也没有必要继续依赖目标页面是否允许脚本注入。

因此,Bug 2015559 是减少该依赖的兼容性背景之一,而不是本次修改成立的唯一原因,也不应被描述为当前调用已被确认禁止。

相关资料:

与 Mozilla 建议的关系

Mozilla 开发者针对扩展文档提出过一种替代方案:将固定逻辑预先包含在扩展页面中,再通过扩展消息触发,而不是由后台动态注入代码。

该建议的原始上下文是 moz-extension: 扩展文档,不能概括为所有跨上下文操作都必须改用消息通信。

对于本处单纯的标签页后退操作,应按以下顺序评估实现:

  1. 优先使用浏览器提供的标签页历史导航 API,例如 chrome.tabs.goBack(req.tabId)
  2. 只有在直接导航 API 无法保持现有行为时,才考虑复用 ScriptCat 现有消息机制,由预先存在的标签页侧代码执行;
  3. 不应仅为了替换这一行注入代码而新增不必要的常驻内容脚本或复杂通信层。

目标

重构安装页交接后的回退流程,使代码直接表达“让被拦截的标签页返回上一页”的意图,并且不再通过 chrome.scripting.executeScript() 执行 history.back()history.go(-1)

重构后:

  • Service Worker 不再为该操作向目标页面动态注入 JavaScript;
  • 优先使用浏览器提供的标签页导航 API;
  • 若直接导航 API 无法满足要求,再采用现有消息机制;
  • 无论安装信息处理成功或失败,都保持当前尝试返回的行为;
  • Chrome 和 Firefox 支持的安装入口不得出现行为回归;
  • 减少后续 Firefox 适配和执行上下文调整中的一处不必要依赖。

范围

  • 替换 ScriptService.listenerScriptInstall() 中用于执行 history.back()chrome.scripting.executeScript() 调用;
  • 保持安装页交接结束后尝试回退原标签页的现有行为;
  • 保证每次安装页交接最多触发一次回退;
  • 只修改完成该职责迁移所需的代码和测试;
  • 根据仓库现有浏览器兼容层决定是否需要对 tabs.goBack() 做轻量封装。

非目标

  • 不声称 Firefox 不支持 scripting.executeScript()
  • 不声称 Mozilla Bug 2015559 已确认阻塞当前全部安装入口;
  • 不要求移除项目中其他 executeScript() 用法;
  • 不重构完整的用户脚本安装流程;
  • 不修改 ExecScript 或完整用户脚本运行时;
  • 不要求为本操作强制引入新的内容脚本消息通道;
  • 不在本 issue 中完成全部 Firefox 支持;
  • 不通过 Firefox 专用跳过逻辑或删除回退功能规避问题。

验收标准

  • 安装后的回退流程不再使用 chrome.scripting.executeScript() 执行 history.back()history.go(-1)
  • 实现优先使用适合标签页历史导航的浏览器 API;
  • 若采用消息方案,必须说明直接导航 API 无法满足的具体原因,并复用现有通信机制;
  • openInstallPageByUrl() 返回成功结果时保持当前回退行为;
  • openInstallPageByUrl() 返回失败结果时保持当前回退行为;
  • 即使出现非预期 rejection,收尾流程也不得重复触发回退;
  • 每次安装页交接最多触发一次回退操作;
  • 支持的 HTTP/HTTPS、file: 和重定向 .user.js 安装入口不得出现行为回归;
  • 不得以 Firefox 专用跳过逻辑代替本次职责迁移。

测试要求

  • 覆盖 openInstallPageByUrl() resolve 为成功结果的路径;
  • 覆盖 openInstallPageByUrl() resolve 为失败结果的路径,因为该方法通常将内部异常转换为 { success: false, msg }
  • 如现有调用链仍保留 finally 语义,补充非预期 rejection 的收尾测试;
  • 验证新的调用每次只触发一次页面回退;
  • 验证该职责不再调用 chrome.scripting.executeScript()
  • 验证回退 API 收到正确的 req.tabId
  • 测试名称遵循仓库现有的中文 BDD 风格;
  • 提交 PR 前运行相关单元测试、pnpm typecheck 和仓库 lint 检查。

Metadata

Metadata

Assignees

No one assigned

    Labels

    proposalTechnical proposal or design discussiontechnicalTechnical implementation, architecture, or refactoring topic

    Type

    Fields

    No fields configured for Task.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions