Google chrome extension Chrome扩展中的RequireJS

Google chrome extension Chrome扩展中的RequireJS,google-chrome-extension,requirejs,Google Chrome Extension,Requirejs,我正在构建一个Chrome扩展,它将一些JavaScript添加到维基百科文章中。据我所知,使用RequireJS的唯一方法是添加行 <script data-main="scripts/bla" src="scripts/require-jquery.js> 您确实可以通过浏览器从Chrome扩展访问页面的DOM,但是内容脚本只能访问由自身创建的JavaScript对象 有很多方法可以包含来自Chrome扩展的脚本,如何包含它将取决于您计划如何使用它 如果您希望它出现在的弹出页面

我正在构建一个Chrome扩展,它将一些JavaScript添加到维基百科文章中。据我所知,使用RequireJS的唯一方法是添加行

<script data-main="scripts/bla" src="scripts/require-jquery.js>

您确实可以通过浏览器从Chrome扩展访问页面的DOM,但是内容脚本只能访问由自身创建的JavaScript对象

有很多方法可以包含来自Chrome扩展的脚本,如何包含它将取决于您计划如何使用它

如果您希望它出现在的弹出页面中,或者您可以将它作为内容脚本包含在清单中,或者使用popup.html中的脚本标记从插件中的相关资源引用它

从舱单:

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://www.google.com/*"],
      "css": ["mystyles.css"],
      "js": ["jquery.js", "myscript.js"]
    }
  ],
  ...
}
从popup.html:

<script data-main="scripts/bla" src="scripts/require-jquery.js>

下面是如何在后台页面中执行此操作

manifest.json
中:

"background": {
    "scripts": [ "scripts/require.js","scripts/main.js"]
}, 
main.js
中:

require.config({
    baseUrl: "scripts"
});

require( [ /*...*/ ], function(  /*...*/ ) {
    /*...*/
});
与此相反:

<script data-main="scripts/bla" src="scripts/require.js></script>

要在内容脚本中使用它,您只需将它作为您的第一个依赖项包含在manifest.json中:

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://www.google.com/*"],
      "css": ["mystyles.css"],
      "js": ["requirejs.js", "myscript.js"]
    }
  ],
  ...
}
它不会污染全局名称空间(窗口),所以不用担心;它仅适用于扩展脚本

此外,在manifest.json中,您必须将requirejs能够使用的文件命名为“web\u可访问的\u资源”,以便轻松地将它们全部放在一个文件夹(例如js/)中,以便使用通配符:

{
  "name": "My extension",
  ...
  "web_accessible_resources": [
     "js/*"
  ],
  ...
}
然后在您的脚本(例如myscript.js)中使用requirejs只需使用
chrome.extension.getURL
请求依赖项,如下所示:

requirejs([chrome.extension.getURL('js/library')], function(library) {
     ...
}

对于普通的香草require.js,下面的编辑仍然是正确的,但是通过分叉RequireJS找到了一个解决方法

Github:
Bower:Bower安装浏览器扩展的requirejs

原始桩

将其注入内容脚本是迄今为止最困难的。以上答案不完整或不正确

背景和弹出窗口:
按照@nafis前面的回答,它们会起作用的

内容脚本
这是一个非常棘手的问题,关键在于:

执行环境
内容脚本在称为隔离世界的特殊环境中执行。它们可以访问所注入页面的DOM,但不能访问页面创建的任何JavaScript变量或函数。对于每个内容脚本,它看起来就像在其运行的页面上没有其他JavaScript执行一样。反过来也是如此:页面上运行的JavaScript不能调用任何函数或访问内容脚本定义的任何变量

直觉上这应该是正确的
manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://www.google.com/*"],
      "css": ["mystyles.css"],
      "js": ["requirejs.js", "myscript.js"]
    }
  ],
  ...
  "web_accessible_resources": [
     "js/*"
  ],
 ...
}
myscript.js

require(["myFancyModule"], function (FM) {
   ...
});
/**
 * Inject the plugin straight into requirejs
 */
define("Injector", {
  load: function (name, req, onload, config) {

    //Load the script using XHR, from background
    var oReq = new XMLHttpRequest();
    oReq.addEventListener("load", function () {

      //Find depenencies in the script, and prepend the
      //Injector! plugin, forcing the load to go through this
      //plugin.
      var modified = getDeps(oReq.response)

      //have requirejs load the module from text
      //it will evaluate the define, and process dependencies
      onload.fromText(modified);
    });
    oReq.open("GET", req.toUrl(name) + ".js");
    oReq.send();

    //Find dependencies and prepend Injector!
    function getDeps(script)
    {
      //extract the define call, reduced to a single line
      var defineCall = script.match(/define([\s\S])*?{/m)[0].split("\n").join("");
      //extract dependenceis from the call
      var depsMatch = defineCall.match(/\[([\s\S]*?)\]/);

      //if there are dependencies, inject the injectors
      if (depsMatch)
      {
        var deps = depsMatch[0];
        var replaced = deps.replace(/(\'|\")([\s\S]*?)\1/g, '$1Injector!$2$1');
        return script.replace(/define([\s\S]*?)\[[\s\S]*?\]/m, 'define$1' + replaced);
      }
      //no dependencies, return script
      return script;
    }
  }
});

/**
 * Call all your dependencies using the plugin
 */
require(["Injector!myFancyModule"], function (FM) {
      chrome.storage.local.get({something});
});
这行不通

问题是requirejs将通过在标题中注入
标记来加载所有依赖项。这些脚本标记在页面环境中执行,而不是在特殊的扩展环境中执行。这很重要

  • 由于页面中未加载requirejs,因此无法加载依赖项 环境
  • 如果网站所有者已经添加了requirejs,可能会发生冲突
  • 正如@Adam所建议的,您可以决定将require.js注入页面,但在这种情况下,您的扩展功能都没有 会有用的。存储、消息传递、跨站点请求都不是 可用
  • 因此,为了让这些功能正常工作,需要将requirejs加载的模块注入到扩展环境中。可以使用requirejs插件来更改负载行为

    由于这种工作方式,解决方案非常不雅观,并且它阻止您在脚本下的调试器中查看脚本。但如果你绝望了,它会起作用的

    myscript.js

    require(["myFancyModule"], function (FM) {
       ...
    });
    
    /**
     * Inject the plugin straight into requirejs
     */
    define("Injector", {
      load: function (name, req, onload, config) {
    
        //Load the script using XHR, from background
        var oReq = new XMLHttpRequest();
        oReq.addEventListener("load", function () {
    
          //Find depenencies in the script, and prepend the
          //Injector! plugin, forcing the load to go through this
          //plugin.
          var modified = getDeps(oReq.response)
    
          //have requirejs load the module from text
          //it will evaluate the define, and process dependencies
          onload.fromText(modified);
        });
        oReq.open("GET", req.toUrl(name) + ".js");
        oReq.send();
    
        //Find dependencies and prepend Injector!
        function getDeps(script)
        {
          //extract the define call, reduced to a single line
          var defineCall = script.match(/define([\s\S])*?{/m)[0].split("\n").join("");
          //extract dependenceis from the call
          var depsMatch = defineCall.match(/\[([\s\S]*?)\]/);
    
          //if there are dependencies, inject the injectors
          if (depsMatch)
          {
            var deps = depsMatch[0];
            var replaced = deps.replace(/(\'|\")([\s\S]*?)\1/g, '$1Injector!$2$1');
            return script.replace(/define([\s\S]*?)\[[\s\S]*?\]/m, 'define$1' + replaced);
          }
          //no dependencies, return script
          return script;
        }
      }
    });
    
    /**
     * Call all your dependencies using the plugin
     */
    require(["Injector!myFancyModule"], function (FM) {
          chrome.storage.local.get({something});
    });
    

    你能再澄清一下吗?通常使用require.js包含模块的方式是通过javascript,而不是脚本标记:require([“some/module”、“a.js”、“b.js”);我知道如何包含模块,但如何在页面加载后包含requireJS本身,并且只使用JavaScript?这并不是对您问题的真正答案,但是你可以简单地创建一个greasemonkey脚本并执行你所有的javascript代码。你可以使用CORS从另一台服务器加载并运行一个脚本。我有一个内容脚本,通常包含它的方式是使用一个带有
    data main
    属性的
    script
    标记。如何在清单文件中指定
    data main
    属性?不,如果从清单中包含属性标记,则无法在内容脚本上添加属性标记。您可以尝试使用编程注入:实际上,编程注入也不起作用,同样的问题(不允许在脚本标记上使用属性)。我建议您不要使用RequireJS,而是将AMD与Almond.js结合使用:-请确保首先使用RequireJS优化器,如r.js:当我使用此方法时,我可以正确加载其他模块,但随后会出现一个错误,即,
    Uncaught ReferenceError:define is not defined
    。这是有道理的,你能让这个工作吗?这应该是公认的答案,因为它实际上解决了这个问题。另外请注意,如果您使用像jsx这样的RequireJS插件,您可能需要在
    manifest.json
    文件中添加
    “content\u security\u policy”:“script src'self”“safe eval';object src'self”“
    ,以便Chrome允许扩展使用
    eval()
    。如果您使用r.js将所有内容捆绑在一起,则可以在生产版本中删除此选项。对此进行否决,因为虽然答案可能在某个时候是正确的,但用户创建的存储库已经有好几年没有重新基于fork了。这不可避免地意味着在以后的时间里会出现潜在的漏洞。@DanAtkinson,很公平,我已经转到了webpack。如果有人偶然发现了这一点,对问题的描述仍然有效。除非您使用r.js打包所有依赖项,否则您必须找到将依赖项加载到“孤立世界”的方法;
    /**
     * Inject the plugin straight into requirejs
     */
    define("Injector", {
      load: function (name, req, onload, config) {
    
        //Load the script using XHR, from background
        var oReq = new XMLHttpRequest();
        oReq.addEventListener("load", function () {
    
          //Find depenencies in the script, and prepend the
          //Injector! plugin, forcing the load to go through this
          //plugin.
          var modified = getDeps(oReq.response)
    
          //have requirejs load the module from text
          //it will evaluate the define, and process dependencies
          onload.fromText(modified);
        });
        oReq.open("GET", req.toUrl(name) + ".js");
        oReq.send();
    
        //Find dependencies and prepend Injector!
        function getDeps(script)
        {
          //extract the define call, reduced to a single line
          var defineCall = script.match(/define([\s\S])*?{/m)[0].split("\n").join("");
          //extract dependenceis from the call
          var depsMatch = defineCall.match(/\[([\s\S]*?)\]/);
    
          //if there are dependencies, inject the injectors
          if (depsMatch)
          {
            var deps = depsMatch[0];
            var replaced = deps.replace(/(\'|\")([\s\S]*?)\1/g, '$1Injector!$2$1');
            return script.replace(/define([\s\S]*?)\[[\s\S]*?\]/m, 'define$1' + replaced);
          }
          //no dependencies, return script
          return script;
        }
      }
    });
    
    /**
     * Call all your dependencies using the plugin
     */
    require(["Injector!myFancyModule"], function (FM) {
          chrome.storage.local.get({something});
    });