Can content scripts and option page scripts use functions in background scripts

I noticed that different background scripts can use each other’s functions, but I don’t seem to be able to use functions in my background scripts from my content scripts.

Ideally, I would have liked to share some functions (e.g. sorting, etc.) across my background, content and options page scripts.

You can still send messages to your background script and it can reply to them.

For example this would give you access to all your functions in the background script:

Background:

browser.runtime.onMessage.addListener(async (data, sender) => {
  switch (data.type) {
    case 'callFn': return window[data.fnName].apply(null, data.params || [])
  }
});
function sort(arr) { return arr }  // just an example...

Then usage from Content script:

const myArray = [2, 1, 3];
const sortedArray = await browser.runtime.sendMessage({type: 'callFn', fnName: 'sort', params: [myArray]});

The only disadvantage here is fact that the process is asynchronous. But usually that’s not an issue and thanks to async / await keywords the usage is pretty simple.

EDIT:
Alternatively if you just looking for a way to reuse your code, you can just extract your common functions into a separate file(s) and then inject them to all those contexts that needs them. For example by creating “utils.js” file and injecting it into all contexts that requires it.

Hi Juraj,
Thank you for your quick answer. I’m aware of messaging between scripts, but I have a lot of async code in my extension and it’s causing some instability issues, i.e. crashes Firefox from time to time.
I’m very interested in your EDIT. Is that documented anywhere. I would need a bit more detailed explanations.

Regarding, docs, I would recommend the anatomy page:

But basically it’s just normal JavaScript thing. The same way you can have multiple scripts loading in one page, you can load multiple script files loading into any of your contexts.

For example, for contexts where you use .html file (like Options page or Popup page), you just include your “utils.js” above your “options.js” script to make sure it get’s loaded before. If you have .html file for your background script, then same way there. If not, then just add it to the manifest file.

Regarding context scripts - again, if you have them defined in the manifest, then just add “utils.js” script before your context script file (they get loaded in the specified order). If you are injecting them dynamically using “executeScript”, the
n just inject your “utils.js” before and await the promise it returns.

Actually what I’m describing here is well described by the webextension-polyfill library.

Just to clarify, all those scripts shares the same window object if they are executed in the same context, that’s why your background scripts can share functions.

Regarding the async code issues you mentioned

I’m a bit skeptical about it :slight_smile:, sure there are some nasty things to be aware of, but if you follow all the rules and make sure there are no race conditions, then it should work 100% time. Huge part of my add-on is now asynchronous and ever since I’ve fixed the race conditions when bootstrapping my add-on, there are no more bug reports.

Thank you for your help, Juraj. I will look into it more deeply.

Btw, I’m looking for some help with an extension that I created. It’s called Context Search. I recently submitted an update (version 3.70) which, unfortunately, had a major bug. I’m not a proficient js developer so I could do with some help.

The extension can be found on AMO here:

and the code source is available on Github, here:

Please let me know if you’d be interested to co-authour and overlook the code. There’s quite a lot to do! Implement folders and drag&drop-ability of search engines in the options page. One user would have liked to be able to have text selected automatically by right-clicking on it, but I discovered that the caret position feature is still experimental.

I’m happy to help with questions, but else I’m crazy busy with my own add-ons and several todo lists :slight_smile: (not to mention I want to refactor everything to TypeScript!).

From what I can see in your code, I would suggest you to use async / await instead of .then, it makes code much more readable (true story). Also it allows some crazy easy constructs, like:

const data = Cache.getData() || await Server.getData() || defaultData;

No problems. I appreciate your helping out. Your website Fast addons looks cool. You seem to have quite a few addons to look after and maintain.

Btw, have you been able to monetize your work? I received a one-time donation of $20 about a year ago and that was it. Doesn’t cover the hundreds of hours spent developing but I enjoy it (when things work!).

Nope :slight_smile:, it’s really bad. I make less than 100€ per month from donations (including Patreon) and I’m working on my add-ons full time plus weekends :smiley:.

The only way to make money is creating premium features and selling them. From my experience about 1% of users is willing to buy the premium feature if it’s good enough. However I had to cancel this business model due to some complications with tax related crap in my country.

But since I’m getting out of money, I will try to create some crazy premium features (like end to end encryption) and allow them to only Patreon users - this should provide more stable income and allow me to avoid the bureaucracy with tax.

Also if you want to get more from your donations, you need to make it easy and visible for users.

1 Like