How to use jQuery in chrome extension?

JavascriptJqueryGoogle ChromeAsynchronousGoogle Chrome-Extension

Javascript Problem Overview


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.

Javascript Solutions


Solution 1 - Javascript

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

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

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

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

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

Solution 6 - Javascript

Since manifest 3, anonymous functions are not allowed (neither in background). Jquery.js file usually has anonymous functions You should set a name to them.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionIshanView Question on Stackoverflow
Solution 1 - JavascriptNicoView Answer on Stackoverflow
Solution 2 - JavascriptVikas BansalView Answer on Stackoverflow
Solution 3 - JavascriptXanView Answer on Stackoverflow
Solution 4 - JavascriptArik PamnaniView Answer on Stackoverflow
Solution 5 - JavascriptRuslan NovikovView Answer on Stackoverflow
Solution 6 - JavascriptAlberto PerezView Answer on Stackoverflow