用户脚本扩展中的unsafeWindow是如何实现的?
扩展实现unsafeWindow访问页面主世界对象的核心逻辑
你在DOM中找不到注入的script标签是正常的,用户脚本管理器的实现根本不依赖常规DOM插入script节点的方案,完整逻辑如下:
- 首先明确浏览器扩展的上下文隔离规则:常规content script、你之前尝试的Firefox
userScriptsAPI默认运行环境都是隔离世界(Isolated World),这个环境中的window是和页面自身JS运行的主世界(Main World)做了双向代理的包装对象,你在隔离世界修改window上的属性不会同步到主世界,自然无法完成对页面对象的monkey-patch。 - 无DOM痕迹的主世界注入实现:Manifest V3 扩展可以直接调用
chrome.scripting.executeScript接口,传入world: 'MAIN'配置参数,就能把代码直接注入到页面主世界上下文执行;老版Manifest V2 扩展的tabs.executeScript也支持对应配置,Firefox 专属的userScriptsAPI同样可以通过配置world: "MAIN"直接进入主世界执行。这种注入方式是浏览器底层直接把代码丢进页面的JS执行上下文,不会在DOM树中生成任何<script>元素,这就是你检查DOM找不到注入痕迹的原因。 unsafeWindow的桥接逻辑:以Violentmonkey为例,它会分两批注入代码:一批直接注入到主世界执行,这部分代码拿到的global/globalThis就是页面真实的顶层window对象,不需要额外定义;另一批运行在隔离世界,负责给用户脚本提供GM相关的API能力。两部分代码通过DOM事件、postMessage或者临时挂载在共享DOM节点上的属性做跨上下文通信,把主世界的真实window引用包装成unsafeWindow对象暴露给用户脚本,用户脚本对unsafeWindow的所有读写、方法调用都会被转发到主世界的真实对象上,直接完成monkey-patch操作。
你之前读源码漏了关键上下文:你看到的src/injected/web/gm-api-wrapper.js属于直接注入到主世界的代码包,这个文件里引用的global就是主世界执行环境默认的顶层全局对象,和你在页面开发者工具控制台里访问的window完全是同一个实例,自然不需要在源码里额外做赋值定义。
内容的提问来源于stack exchange,提问作者TheDcoder
相关产品推荐
相关产品推荐

