涉及模块
src/app/service/service_worker/script.ts
- Service Worker 与标签页侧执行上下文之间的通信
- 用户脚本安装完成后的页面返回流程
当前实现
ScriptService.listenerScriptInstall() 会拦截用户脚本安装地址并打开 ScriptCat 的安装页面。
当 openInstallPageByUrl() 完成或失败后,当前代码都会在 finally 中调用 chrome.scripting.executeScript(),向原标签页注入一个函数并执行:
因此,当前安装流程为了完成一次“返回上一页”操作,需要由 Service Worker 主动向目标标签页注入并执行代码。
本 issue 只针对上述安装后返回流程,不涉及 ScriptCat 用于执行用户脚本的 ExecScript 类,也不讨论完整的用户脚本运行时设计。
问题说明
需要避免一种容易引起误解的表述:
Firefox 不允许扩展使用 scripting.executeScript()。
这并不准确。Firefox 支持 scripting.executeScript();当前调用本身也不应被描述为一个已确认的 Firefox 阻塞问题。
本 issue 真正要处理的是执行职责和上下文边界:
history.back() 属于标签页页面历史操作;
- 目前该操作由 Service Worker 通过一次性脚本注入触发;
- 这使安装流程额外依赖 Service Worker 对另一个执行上下文的直接代码执行;
- 对于这样一个固定且明确的页面动作,更清晰的模型是由标签页侧上下文预先拥有对应逻辑,并在收到请求后自行执行。
因此,本 issue 的目标不是因为 Firefox 禁用了某个 API,也不是要全面移除项目中的 executeScript(),而是消除这一处仅为触发 history.back() 而存在的一次性跨上下文代码注入。
Rob Wu 的观点
原始 issue 所引用的 Rob Wu 意见,其核心可概括为:
不应把模型设计成“上下文 A 直接把代码放到上下文 B 中执行”;更合适的方式是“上下文 A 向上下文 B 发送请求,再由上下文 B 执行自己拥有的代码”。
这里需要明确:
- 上述内容是对 Rob Wu 架构意见的概括,不是 Mozilla API 文档的逐字规范;
- 它表达的是推荐的执行职责划分和消息通信模式;
- 它不能被解释成 Firefox 已禁止所有
scripting.executeScript() 调用。
本 issue 采用这一观点,是因为 history.back() 本来就是一个由标签页侧上下文执行更自然的固定操作,而不是因为当前 API 在 Firefox 中必然不可用。
官方资料
这些资料用于说明 API 能力和标准的跨上下文通信方式,不应被引用为“Firefox 禁止 executeScript()”的依据。
目标
将用户脚本安装完成后的“返回上一页”职责移交给合适的标签页侧上下文。
重构后:
- Service Worker 不再为了执行
history.back() / history.go(-1) 而向标签页动态注入函数;
- 页面返回动作由标签页侧预先存在的代码自行执行;
- Service Worker 如需触发该动作,应通过 ScriptCat 现有的消息通信机制发送明确请求;
- Chrome 中现有安装体验保持不变;
- 同时减少后续 Firefox 适配和执行上下文重构中的一处不必要依赖。
范围
- 替换
ScriptService.listenerScriptInstall() 中用于执行 history.back() 的 chrome.scripting.executeScript() 调用;
- 保持当前行为:无论
openInstallPageByUrl() 成功还是失败,安装页交接结束后都应尝试返回原页面;
- 复用项目已有的消息通信和执行上下文边界;
- 只修改完成该职责迁移所必需的代码和测试。
具体实现由贡献者在梳理现有 content、scripting 和消息通道后决定,本 issue 不预设完整方案。
非目标
- 不声称 Firefox 不支持
scripting.executeScript();
- 不要求移除项目中所有
executeScript() 用法;
- 不重构完整的用户脚本安装流程;
- 不修改
ExecScript 用户脚本运行时;
- 不在本 issue 中完成全部 Firefox 支持;
- 不通过在 Firefox 中隐藏或删除返回功能来规避问题;
- 不进行与该职责无关的模块清理。
验收标准
- 安装后的返回流程不再使用
chrome.scripting.executeScript() 执行 history.back() 或 history.go(-1);
- 页面历史操作由合适的标签页侧上下文自行完成;
- 跨上下文触发通过 ScriptCat 已有的消息机制完成;
openInstallPageByUrl() 成功和失败时均保持当前返回行为;
- 每次安装页交接只触发一次返回操作;
- 支持的
.user.js 安装入口不得出现行为回归;
- 不得以 Firefox 专用跳过逻辑代替本次职责迁移。
测试要求
- 覆盖
openInstallPageByUrl() resolve 和 reject 两条路径,因为当前返回行为位于 finally 中;
- 验证新的消息或调用只触发一次页面返回;
- 验证该职责不再调用
chrome.scripting.executeScript();
- 测试名称遵循仓库现有的中文 BDD 风格;
- 提交 PR 前运行相关单元测试、
pnpm typecheck 和仓库 lint 检查。
涉及模块
src/app/service/service_worker/script.ts当前实现
ScriptService.listenerScriptInstall()会拦截用户脚本安装地址并打开 ScriptCat 的安装页面。当
openInstallPageByUrl()完成或失败后,当前代码都会在finally中调用chrome.scripting.executeScript(),向原标签页注入一个函数并执行:因此,当前安装流程为了完成一次“返回上一页”操作,需要由 Service Worker 主动向目标标签页注入并执行代码。
本 issue 只针对上述安装后返回流程,不涉及 ScriptCat 用于执行用户脚本的
ExecScript类,也不讨论完整的用户脚本运行时设计。问题说明
需要避免一种容易引起误解的表述:
这并不准确。Firefox 支持
scripting.executeScript();当前调用本身也不应被描述为一个已确认的 Firefox 阻塞问题。本 issue 真正要处理的是执行职责和上下文边界:
history.back()属于标签页页面历史操作;因此,本 issue 的目标不是因为 Firefox 禁用了某个 API,也不是要全面移除项目中的
executeScript(),而是消除这一处仅为触发history.back()而存在的一次性跨上下文代码注入。Rob Wu 的观点
原始 issue 所引用的 Rob Wu 意见,其核心可概括为:
这里需要明确:
scripting.executeScript()调用。本 issue 采用这一观点,是因为
history.back()本来就是一个由标签页侧上下文执行更自然的固定操作,而不是因为当前 API 在 Firefox 中必然不可用。官方资料
scripting.executeScript()仍是 Firefox 支持的 WebExtensions APIhttps://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/executeScript
tabs.executeScript()的code字符串参数https://extensionworkshop.com/documentation/develop/manifest-v3-migration-guide/#scripting-api
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/sendMessage
这些资料用于说明 API 能力和标准的跨上下文通信方式,不应被引用为“Firefox 禁止
executeScript()”的依据。目标
将用户脚本安装完成后的“返回上一页”职责移交给合适的标签页侧上下文。
重构后:
history.back()/history.go(-1)而向标签页动态注入函数;范围
ScriptService.listenerScriptInstall()中用于执行history.back()的chrome.scripting.executeScript()调用;openInstallPageByUrl()成功还是失败,安装页交接结束后都应尝试返回原页面;具体实现由贡献者在梳理现有 content、scripting 和消息通道后决定,本 issue 不预设完整方案。
非目标
scripting.executeScript();executeScript()用法;ExecScript用户脚本运行时;验收标准
chrome.scripting.executeScript()执行history.back()或history.go(-1);openInstallPageByUrl()成功和失败时均保持当前返回行为;.user.js安装入口不得出现行为回归;测试要求
openInstallPageByUrl()resolve 和 reject 两条路径,因为当前返回行为位于finally中;chrome.scripting.executeScript();pnpm typecheck和仓库 lint 检查。