首页 文章

如何在其他页面脚本之前制作firefox附加内容脚本注入并运行脚本?

提问于
浏览
2

我正在使用浏览器扩展/插件 . 我们在Chrome中使用它,所以我试图让它在Firefox中运行 .

我已经在Firefox Developer Edition 49.0a2(2016-07-25)中加载了我的加载项 .

我的扩展涉及将content_script设置为 run_at: document_start ,因此它可以在其他页面脚本运行之前注入脚本标记,因此它可以使对象全局可用于网站 .

这似乎在Chrome中运行良好,但在Firefox中,它已被证明有点竞争条件,其他页面资源大部分时间都在加载 .

是否有一种策略来加载内容脚本,以便在任何其他页面脚本运行之前注入并加载脚本?

当我添加日志时,我可以很好地隔离发生的事情 . 在此示例内容脚本中:

// inject in-page script
console.log('STEP 1, this always happens first')
var scriptTag = document.createElement('script')
scriptTag.src = chrome.extension.getURL('scripts/inpage.js')
scriptTag.onload = function () { this.parentNode.removeChild(this) }
var container = document.head || document.documentElement
// append as first child
container.insertBefore(scriptTag, container.children[0])

现在如果文件 scripts/inpage.js 只是运行一个日志,就像

console.log('STEP 2, this should always run second')

我用这样的脚本访问一个页面:

console.log('Step 3, the page itself, should run last')

实际上,步骤2和步骤3以非确定性顺序运行 .

非常感谢!

如果您敢于自己尝试,我在特殊分支上的公共存储库中具有与Firefox兼容的脚本版本:https://github.com/MetaMask/metamask-plugin/tree/FirefoxCompatibility

2 回答

  • 0

    带有外部源( <script src> )的动态插入脚本不会阻止脚本的执行,因此无法保证您的脚本会加载 . 如果您的扩展程序在Chrome中运行,那只是纯粹的运气 .

    如果你真的想在其余的脚本之前运行一些脚本,你必须内联运行它:

    var actualCode = `
    // Content of scripts/inpage.js here
    `;
    
    var s = document.createElement('script');
    s.textContent = actualCode;
    (document.head || document.documentElement).appendChild(s);
    s.remove();
    

    理想情况下,您的构建脚本将读取 scripts/inpage.js ,将其序列化为字符串并将其放在 actualCode 变量中 . 但是如果 inpage.js 只是几行代码,那么可以使用上面的代码 .

    请注意,除非绝对必要,否则您将在网页中注入代码 . 原因是页面的执行环境是不可信的 . 如果您在 document_start 注入,那么您可以保存稍后(在闭包中)使用的函数和(原型)方法,但需要非常仔细的编码 .

    如果您的内容脚本不是由构建脚本生成的,并且您仍希望将脚本分开,那么您也可以使用synchronous XMLHttpRequest 来获取脚本 . 出于性能原因,不推荐使用同步XHR,因此使用它需要您自担风险 . 扩展程序代码通常与您的扩展程序捆绑在一起,因此使用sync xhr应该是低风险的:

    // Note: do not use synchronous XHR in production!
    var x = new XMLHttpRequest();
    x.open('GET', chrome.runtime.getURL('scripts/inpage.js'), false);
    x.send();
    var actualCode = x.responseText;
    
    var s = document.createElement('script');
    s.textContent = actualCode;
    (document.head || document.documentElement).appendChild(s);
    s.remove();
    
  • 4

    如果您使用的是基于bootstrap.js的插件,您可以使用framescript和 DOMWindowCreated 来处理文档,甚至在HTML DOM(以前的document.body等基础知识)呈现之前--https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Frame_script_environment#Events - innerHTML将可用但没有脚本会有执行 . 您可以将内联脚本放在@Rob提到的顶部 .

相关问题