Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome Extension js: Sharing functions between background.js and popup.js

Suppose I have a JavaScript function foo() which I want to execute in both the background and in popup.html.

For example: it is executed every hour in the background of my Chrome extension, but can also be activated by the user from the popup menu (popup.html) on a button click.

I currently have a global.js script which defines foo() and when I include calls to foo() in my popup.js document, they execute without issue. (If I include both scripts in popup.html)

However, when I try to access foo() inside background.js, the calls do not execute (even if global.js is included in the "background" "manifest.json" extension file:

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

Is there a convenient way to share functions between background.js and popup.js (without copying the entire function into each)?

like image 560
user244718 Avatar asked Mar 29 '14 23:03

user244718


2 Answers

The background scripts are loaded in the order specified in the manifest file. Simply load the file with common code before your background script as follows:

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

Instead of duplicating the code in the popup, you can also use chrome.extension.getBackgroundPage() from the popup to access functions/variables of the background page, e.g. chrome.extension.getBackgroundPage().myFunction();.

like image 67
Rob W Avatar answered Nov 15 '22 22:11

Rob W


You can also call functions from other scripts almost as if you had imported them all directly. You can do this by using constructors, and custom prototypes.

First add the background scripts to the mainfest, in order of access, as well as linked as scripts in our popup.html before the closing body tag:

manifest.json

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

In the file foo.js we create our object prototype. I'm using a module pattern, because we want it to be private otherwise:

foo.js

(() => {
  console.log('foo loaded');       // check that the script has loaded
  window.test = window.test || {}; // check for or create the object

  test.FooFunc = function() {      // setup a constructor to hold defaults
    this.foo = 'bar',
    this.time = '15000'
  }

  test.FooFunc.prototype = {       // add our prototype with a single method
    callConsole: (text) => {
      console.log('FooFunc method loaded from ' + text);
    }
  }
})();

From the bg.js file we can call this function constantly by instantiating a new test object.

bg.js

(() => {
  console.log('bg loaded');            // check that the script has loaded
  var testProto = new test.FooFunc;    // instantiate new test object

  testProto.callConsole('Background!');
})();

After loading the files, and as soon as the Icon is clicked the Pop-up opens, the scripts fire, including our function. You should see something like this in your console:

foo loaded
bg loaded
FooFunc method loaded from Background!

Using Multiple Background Scripts

Of course we can continue to add more scripts into the mix by simply adding them to the background script list, and popup.html before the bg.js, *in the order you want them to be accessed**. Once added, make new prototypes to the test object from the new scripts in the same manor, and then adding methods to each (test.Prefs is a great one to make).

*Scripts are loaded in order they are called, so if the prototype is not created before a script that wants to access it, it will not be able to find the new prototype. Any script can access the prototypes as long as they are created before those scripts are called.

For a great example of this in a use-case scenario, you can check out Chrome's Buildbot Monitor. It not only shows a great process of working with multiple scripts privately, but also how you can use a single object to hold multiple settings, prototypes, and methods for your extension to access.

like image 4
DBrown Avatar answered Nov 15 '22 23:11

DBrown