How to use jQuery in chrome extension?

135,150

Solution 1

You have to add your jquery script to your chrome-extension project and to the background section of your manifest.json like this :

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

If you need jquery in a content_scripts, you have to add it in the manifest too:

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

This is what I did.

Also, if I recall correctly, the background scripts are executed in a background window that you can open via chrome://extensions.

Solution 2

Its very easy just do the following:

add the following line in your manifest.json

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

Now you are free to load jQuery directly from url

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

Source: google doc

Solution 3

And it works fine, but I am having the concern whether the scripts added to be executed in this manner are being executed asynchronously. If yes then it can happen that work.js runs even before jQuery (or other libraries which I may add in future).

That shouldn't really be a concern: you queue up scripts to be executed in a certain JS context, and that context can't have a race condition as it's single-threaded.

However, the proper way to eliminate this concern is to chain the calls:

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'
        });
    });
});

Or, generalized:

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);

Or, promisified (and brought more in line with the proper signature):

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)
);

Or, why the heck not, async/await-ed for even clearer syntax:

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);
}

Note, in Firefox you can just use browser.tabs.executeScript as it will return a Promise.

Solution 4

Apart from the solutions already mentioned, you can also download jquery.min.js locally and then use it -

For downloading -

wget "https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"

manifest.json -

"content_scripts": [
   {
    "js": ["/path/to/jquery.min.js", ...]
   }
],

in html -

<script src="/path/to/jquery.min.js"></script>

Reference - https://developer.chrome.com/extensions/contentSecurityPolicy

Solution 5

In my case got a working solution through Cross-document Messaging (XDM) and Executing Chrome extension onclick instead of page load.

manifest.json

{
  "name": "JQuery Light",
  "version": "1",
  "manifest_version": 2,

  "browser_action": {
    "default_icon": "icon.png"
  },

  "content_scripts": [
    {
      "matches": [
        "https://*.google.com/*"
      ],
      "js": [
        "jquery-3.3.1.min.js",
        "myscript.js"
      ]
    }
  ],

  "background": {
    "scripts": [
      "background.js"
    ]
  }

}

background.js

chrome.browserAction.onClicked.addListener(function (tab) {
  chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
    var activeTab = tabs[0];
    chrome.tabs.sendMessage(activeTab.id, {"message": "clicked_browser_action"});
  });
});

myscript.js

chrome.runtime.onMessage.addListener(
    function (request, sender, sendResponse) {
        if (request.message === "clicked_browser_action") {
        console.log('Hello world!')
        }
    }
);
Share:
135,150

Related videos on Youtube

Ishan
Author by

Ishan

I make applications running on the entire tech stack from consumer-facing devices to the machines supporting those devices. I try to keep optimizing the performance of the devices/servers that my programs run on. Currently working as a Senior Software Engineer at Myntra.

Updated on December 15, 2021

Comments

  • Ishan
    Ishan over 2 years

    I am writing a chrome extension. And I want to use jQuery in my extension. I am not using any background page, just a background script.

    Here are my files :

    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"
        }
    }
    

    My background.js file just runs another file named work.js

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

    The main logic of my extension is inside work.js. The contents of which I don't think matters here for this question.

    What I want to ask is how can I use jQuery in my extension. Since I am not using any background page. I can't just add jQuery to it. So how can I add and use jQuery into my extension ?

    I tried running jQuery along with my work.js from background.js file.

    // 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'
        });
    });
    

    And it works fine, but I am having the concern whether the scripts added to be executed in this manner are being executed asynchronously. If yes then it can happen that work.js runs even before jQuery (or other libraries which I may add in future).

    And I would also like to know what's the correct and best way to use third party libraries, in my chrome extension.

    • bjb568
      bjb568 over 9 years
      The correct way is to go vanilla!
    • Pro Q
      Pro Q over 7 years
      If you are here looking for how to add jQuery to a pop-up extension (as I was), see this question: stackoverflow.com/questions/12035242/…
  • Ishan
    Ishan over 10 years
    Well what do you exactly mean by You have to add your jquery script to your chrome-extension project ? I did this : manifest.json : "background": { ` "scripts": ["thirdParty/jquery-2.0.3.js", "background.js"],` ` "persistent": false` ` },` and I have downloaded the jQuery to thirdParty folder. However I still can't use jQuery. It give the error : Uncaught ReferenceError: $ is not defined my added this to my work.js file for testing. $("body").html("Foo!");
  • Ishan
    Ishan over 10 years
    The above comment looks like a mess but while adding comments preview is not shown. Please forgive me for that.
  • Nico
    Nico over 10 years
    I mean to add it to your chrome-extension folder. Like /home/you/chromexetension_source_files/thirdParty/jquery-2.0‌​.3.js. You should do the same thing with your work.js.
  • Ishan
    Ishan over 10 years
    I tried doing what you said. But I am still getting the same error of not being able to access jquery from my work.js file. Uncaught ReferenceError: $ is not defined. If you can, can you please upload a working example somewhere. Just a simple example like doing '$("body").html("Foo!");' in work.js.
  • Nico
    Nico over 10 years
    @ishan I can't really help you, this is what I did and I have jquery in my background.js script.
  • Nico
    Nico over 10 years
    @ishan Have you tried to add {"runAt":"document_end"} in your chrome.tabs.executeScript call ? Like chrome.tabs.executeScript({file: 'work.js', runAt:'document_end'})
  • BenR
    BenR over 9 years
    I also had trouble getting jQuery or $ to be recognized. Turned out I was referencing jQuery last in the manifest array. When I put it first it was recognized.
  • user889030
    user889030 about 9 years
    in your chrome extension project folder , make your have thirdParty folder and you have jquery.1.10.2.min.js file in it (( thirdParty/jquery.1.10.2.min.js ))
  • alayli
    alayli almost 9 years
    Page already has jQuery. Is there a way to use web site's jQuery?
  • Nico
    Nico almost 9 years
    @alayli I'm not sure about this but the background page is a page of it's own so it needs the lib. The content script should be able to use whatever is publicly available in the page it is injected. I think you don't necessarily need a background page so if you want your extension to depends on the injected page dependency, it's up to you.
  • another
    another over 7 years
    What if you have multiple scripts to load?
  • D. Woods
    D. Woods almost 7 years
    @BenR - Your comment is truly a solution (at least for my needs with respect to getting a script loaded via content_script to find and use functions from the jQuery library).
  • c-an
    c-an over 5 years
    This is the best way... You don't need the html part.
  • Nathaniel Verhaaren
    Nathaniel Verhaaren about 5 years
    Great answer if you want to load your script from a remote server (which effectively requires that you trust the remote server with your extension and everything it has access to).
  • Dan Atkinson
    Dan Atkinson almost 5 years
    @NathanielVerhaaren This is a reasonable point to raise, but it can be mitigated by verifying the source using subresource integrity (SRI).
  • FriskySaga
    FriskySaga about 4 years
    The first method is brilliant. As someone who doesn't know much JavaScript, I never considered something like that.
  • Manik
    Manik over 3 years
    in manifest V3 this manifest will give this error: The "background.scripts" key cannot be used with manifest_version 3. Use the "background.service_worker" key instead. Could not load manifest. so we have to use background.service_workers like this: background": {"service_workers": ["thirdParty/jquery-2.0.3.js", "background.js"]}