16

Let's say, I have a function:

var rand = function(n) {
    return Math.floor(Math.random() * n);
}

Can I use this function in both Content Script and Background Script without copypaste?

Thank you.

Oleg
  • 22,300
  • 9
  • 68
  • 84

2 Answers2

28

Yes. You could have an external JS file which is loaded as part of the background and the content script (like any normal JS file). Just add it to the background and content script file arrays in the manifest and it will be loaded for you.

For example if our shared function reside in sharedFunctions.js, the content script using them is in mainContentScript.js and the background code in mainBackground.js (all in the js subfolder) we can do something like this in the manifest:

 "background": {
   "scripts": [ "js/sharedFunctions.js", "js/mainBackground.js" ]
 },

 "content_scripts": [
    {
      "matches": ["*://*/*"],
      "js": ["js/sharedFunctions.js", "js/mainContentScript.js"]
    }
 ]

Note: Make sure to load it in the right order, before other files using it.

Or you can also add it as a script tag (with a relative URL) in the background.html and in the manifest only add it to the content script's JS array. So the manifest will look like:

 "background": {
   "page": "background.html"
 },
 "content_scripts": [
     {
       "matches": ["*://*/*"],
       "js": ["js/sharedFunctions.js", "js/mainContentScript.js"]
     }
  ]

and the background.html file will have this script tag:

 <script type="text/javascript" src="js/sharedFunctions.js"></script>

Edit: Also, For sharing with other scopes in other parts of the extension (unfortunately not available in the content script).

You can also have the functions you want to share reside in the background script and reach them via chrome.runtime.getBackgroundPage() which you can read more about here: https://developer.chrome.com/extensions/runtime#method-getBackgroundPage

So, let's say you have your rand() function declared as a global variable in the background script (which means it's a property on the background's window object), you can do something of this sort at the beginning the script in the other scope (this can be a popup context like a browserAction window):

var background, newRandomNumber;
chrome.runtime.getBackgroundPage(function(backgroundWindow){
 background = backgroundWindow;
 newRandomNumber = background.rand();
})

This way you can also use the variable background to access any property or method set on the background's window object. Be mindful, that this function runs asynchrounusly, meaning that only after the callback is called will the variables background and newRandomNumber will be defined.

Lior
  • 1,599
  • 17
  • 21
  • 1
    One needs to be extremely mindful of the latter part; `chrome.runtime.getBackgroundPage` is asynchronous, which is not easy to grasp for novices. And the reason it is asynchronous are the Event pages. If an Event page is used for a background script, it will be fully "spun up" for this call, potentially very costly. – Xan Jun 15 '14 at 09:05
  • Thank you guys) I appreciate your help. I have one more question: my content script consists of this only line: `console.log(chrome.runtime.getBackgroundPage);`. Why do I get `undefined` in the console? How do I enable `getBackgroundPage` method? I use Chrome 34.0.1847.116 under Linux Mint – Oleg Jun 15 '14 at 09:17
  • 1
    @CuriousGuy This method is not actually available for Content Scripts. See [here](https://developer.chrome.com/extensions/content_scripts). The only two channels to communicate between them are Messaging and `chrome.storage`. – Xan Jun 15 '14 at 09:39
  • @Xan You are right, my bad, I will edit my answer accordingly so that will be noted. – Lior Jun 15 '14 at 09:42
  • @Xan, I felt like I was doing something wrong. Now all thing are clear to me. Thank you very much – Oleg Jun 15 '14 at 09:59
1

Yes, you can, by putting it in a separate JS file and loading it in both.

Say, you have a file utils.js that contain all such functions.

Then you can load the background page like this:

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

And the content script like this:

"content_scripts": [
  {
    "matches": ["..."],
    "js": ["utils.js", "content.js"]
  }
],

Or, if you're using programmatic injection, chain the calls like this:

chrome.tabs.executeScript(tabId, {file: "utils.js"}, function(){
  chrome.tabs.executeScript(tabId, {file: "content.js"}, yourActualCallback);
});
Xan
  • 74,770
  • 16
  • 179
  • 206