RequireJS в расширении Chrome - PullRequest
16 голосов
/ 30 января 2012

Я создаю расширение для Chrome, которое добавляет JavaScript в статьи Википедии. Насколько я знаю, единственный способ использовать RequireJS - это добавить строку

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

Однако в моем расширении Chrome у меня нет доступа к HTML, чтобы добавить эту строку. Есть предложения?

Ответы [ 4 ]

20 голосов
/ 30 января 2012

У вас есть доступ к DOM страницы из расширения Chrome с помощью скрипта контента , однако скрипт контента будет иметь доступ только к объектам 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>

Если вы хотите его на фоновой странице , вы можете ссылаться на него с фоновой страницы, используя тег script из относительного ресурса в вашем плагине.

Из background.html

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

Если вы хотите, чтобы он был включен в саму страницу браузера, вам нужно использовать динамическое внедрение скриптов в DOM страницы. У вас есть доступ к DOM страницы из скрипта контента . Обратите внимание, что если вы загружаете JavaScript, используя эту технику, вы подключаете JavaScript (с фоновой страницы, скрипта контента или скрипта всплывающих окон), и не будете иметь к нему доступа.

Вы можете загрузить requirejs из вашего добавочного номера с помощью метода chrome.extension.getURL или из расположенного в Интернете местоположения.

var script = document.createElement('script');
script.setAttribute("type", "text/javascript");
script.setAttribute("async", true);
script.setAttribute("src", chrome.extension.getURL("require-jquery.js"));  
//Assuming your host supports both http and https
var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
head.insertBefore(script, head.firstChild)
16 голосов
/ 08 апреля 2014

Вот как это можно сделать на фоновой странице.

В 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>

Вы должны использовать это:

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

См. этот вопрос - Использование Require.js без data-main

Вы также можете сделать то же самое на странице содержимого, используя этот принцип.

Хороший вопрос, кстати.Мне понравились ответы Адама Айреса .

3 голосов
/ 11 сентября 2016

РЕДАКТИРОВАТЬ ниже все еще верно для простого vanilla require.js, но нашел обходной путь путем разветвления RequireJS

Github: https://github.com/jeroendelau/requirejs
Bower: установка bower requirejs-for-browser-extensions

ОРИГИНАЛЬНАЯ ПОЧТА

Внедрить его в скрипт контента - безусловно, самое сложное. И приведенные выше ответы являются неполными или неправильными.

Фон и всплывающее окно:
Пойдите с более ранним ответом @nafis, они будут работать

Сценарий содержания
Это очень сложный вопрос, и эта часть из описания API является ключевой:

Среда исполнения
Сценарии содержимого выполняются в специальной среде, называемой изолированным миром. Они имеют доступ к 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) {
   ...
});

ЭТО НЕ БУДЕТ РАБОТАТЬ

Проблема в том, что requirejs продолжит загрузку всех ваших зависимостей, введя теги <script> в заголовок. Эти теги сценария выполняются в среде PAGE, а не в специальной среде EXTENSION. И это имеет значение.

  1. Зависимости не загружаются, так как requirejs не загружается на странице окружающая среда
  2. Если владелец сайта уже добавил requirejs, это может привести к конфликту
  3. Вы можете принять решение внедрить require.js на страницу, как предлагает @Adam, но в этом случае ни одна из ваших расширенных функций буду работать. хранение, обмен сообщениями, межсайтовый запрос - все это не доступны

Таким образом, чтобы они работали, модули, загруженные requirejs, должны быть внедрены в среду расширений. Для изменения поведения загрузки можно использовать плагин requirejs.

Из-за того, как это работает, решение очень не элегантное, и оно мешает вам видеть сценарии в отладчике под сценариями. Но если вы в отчаянии, это сработает.

myscript.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});
});
2 голосов
/ 22 сентября 2015

Чтобы использовать его в скрипте содержимого , вы можете просто включить его в manifest.json как first зависимость:

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

Это НЕ загрязнит глобальное пространство имен (окно), так что об этом не стоит беспокоиться; он доступен только для расширенных скриптов.

Также в manifest.json вы должны назвать файлы, которые сможет использовать requirejs, назвав их «web_accessible_resources», чтобы упростить их размещение в папке (например, js /), чтобы вы могли использовать подстановочный знак :

{
  "name": "My extension",
  ...
  "web_accessible_resources": [
     "js/*"
  ],
  ...
}

А затем в вашем скрипте (например, myscript.js) для использования requirejs просто запросите зависимости с помощью chrome.extension.getURL, например:

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