Как использовать jQuery в chrome extension?

Я пишу хром-расширение. И я хочу использовать jQuery в своем расширении. Я не использую какую-либо справочную страницу, просто фона script.

Вот мои файлы:

manifest.json

{
    "manifest_version": 2,

    "name": "Extension name",
    "description": "This extension does something,",
    "version": "0.1",

    "permissions": [
        "activeTab"
    ],

    "browser_action": {
        "default_icon": "images/icon_128.png"
    },

    "background": {
        "scripts": ["background.js"],
        "persistent": false
    },

    "icons": {
        "16": "images/icon_16.png",
        "48": "images/icon_48.png",
        "128": "images/icon_128.png"
    }
}

Мой файл background.js запускает еще один файл с именем work.js

// Respond to the click on extension Icon
chrome.browserAction.onClicked.addListener(function (tab) {
    chrome.tabs.executeScript({
        file: 'work.js'
    });
});

Основная логика моего расширения находится внутри work.js. Содержание, о котором я не думаю, имеет значение здесь для этого вопроса.

Я хочу спросить, как я могу использовать jQuery в своем расширении. Поскольку я не использую какую-либо справочную страницу. Я не могу просто добавить к нему jQuery. Итак, как я могу добавить и использовать jQuery в своем расширении?

Я попытался запустить jQuery вместе с моим файлом work.js из background.js.

// Respond to the click on extension Icon
chrome.browserAction.onClicked.addListener(function (tab) {
    chrome.tabs.executeScript({
        file: 'thirdParty/jquery-2.0.3.js'
    });
    chrome.tabs.executeScript({
        file: 'work.js'
    });
});

И это прекрасно работает, но я обеспокоен тем, выполняются ли сценарии, выполненные таким образом, асинхронно. Если да, то может случиться, что work.js работает даже до jQuery (или других библиотек, которые я могу добавить в будущем).

И я также хотел бы знать, какой правильный и лучший способ использовать сторонние библиотеки, в моем расширении chrome.

Ответ 1

Вы должны добавить свой jquery script в проект chrome-extension и в раздел background вашего manifest.json следующим образом:

  "background":
    {
        "scripts": ["thirdParty/jquery-2.0.3.js", "background.js"]
    }

Если вам нужен jquery в content_scripts, вы также должны добавить его в манифест:

"content_scripts": 
    [
        {
            "matches":["http://website*"],
            "js":["thirdParty/jquery.1.10.2.min.js", "script.js"],
            "css": ["css/style.css"],
            "run_at": "document_end"
        }
    ]

Это то, что я сделал.

Кроме того, если я правильно помню, фоновые скрипты выполняются в фоновом окне, которое вы можете открыть через chrome://extensions.

Ответ 2

Очень просто сделать следующее:

добавьте следующую строку в свой файл mainfest.json

"content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'",

теперь вы можете бесплатно загружать jquery из url

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>

Источник: google doc

Ответ 3

И это прекрасно работает, но я обеспокоен тем, выполняются ли сценарии, выполненные таким образом, асинхронно. Если да, то может случиться, что work.js работает даже до jQuery (или других библиотек, которые я могу добавить в будущем).

Это не должно вызывать беспокойства: вы создаете очереди сценариев, которые должны выполняться в определенном контексте JS, и этот контекст не может иметь состояние гонки, поскольку он однопоточен.

Однако правильный способ устранить эту проблему состоит в цепочке вызовов:

chrome.browserAction.onClicked.addListener(function (tab) {
    chrome.tabs.executeScript({
        file: 'thirdParty/jquery-2.0.3.js'
    }, function() {
        // Guaranteed to execute only after the previous script returns
        chrome.tabs.executeScript({
            file: 'work.js'
        });
    });
});

Или, обобщенный:

function injectScripts(scripts, callback) {
  if(scripts.length) {
    var script = scripts.shift();
    chrome.tabs.executeScript({file: script}, function() {
      if(chrome.runtime.lastError && typeof callback === "function") {
        callback(false); // Injection failed
      }
      injectScripts(scripts, callback);
    });
  } else {
    if(typeof callback === "function") {
      callback(true);
    }
  }
}

injectScripts(["thirdParty/jquery-2.0.3.js", "work.js"], doSomethingElse);

Или, обещал (и дал больше в соответствии с соответствующей подписью):

function injectScript(tabId, injectDetails) {
  return new Promise((resolve, reject) => {
    chrome.tabs.executeScript(tabId, injectDetails, (data) => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError.message);
      } else {
        resolve(data);
      }
    });
  });
}

injectScript(null, {file: "thirdParty/jquery-2.0.3.js"}).then(
  () => injectScript(null, {file: "work.js"})
).then(
  () => doSomethingElse
).catch(
  (error) => console.error(error)
);

Или, почему heck not, async/await -ed для еще более четкого синтаксиса:

function injectScript(tabId, injectDetails) {
  return new Promise((resolve, reject) => {
    chrome.tabs.executeScript(tabId, injectDetails, (data) => {
      if (chrome.runtime.lastError) {
        reject(chrome.runtime.lastError.message);
      } else {
        resolve(data);
      }
    });
  });
}

try {
  await injectScript(null, {file: "thirdParty/jquery-2.0.3.js"});
  await injectScript(null, {file: "work.js"});
  doSomethingElse();
} catch (err) {
  console.error(err);
}

Обратите внимание: в Firefox вы можете просто использовать browser.tabs.executeScript, поскольку он вернет обещание.