Reputation: 7271
I'm working on a Chrome extension with many content scripts. Most of them use the same function(s), so I'd like to share those functions between the content scripts; however I can't seem to figure out how to do it.
Content scripts are sandboxed, so don't have access to the same window
object. It seems there should be an obvious solution, but I haven't been able to find it.
Upvotes: 7
Views: 1927
Reputation: 69367
Content scripts are sandboxed, so don't have access to the same window object.
That's not entirely true: although content scripts by default cannot interact with the window
object of the page where they are loaded, they share the same hidden window
object of the "isolated world". So if you load two different content scripts into the same page, you'll be using the same window
for both content scripts.
Here is an example, try it by yourself, and do something like this:
A sample of manifest.json
:
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["one.js", "two.js"]
}
]
}
The script one.js
with the function:
function sayHello(name) {
alert("Hello " + name + "!");
}
The script two.js
that uses that function:
sayHello('John');
That's pretty easy to tell:
one.js
script is injected first and defines the sayHello
functiontwo.js
and any other content script injected after one.js
can use that functionsayHello('John');
will alert "Hello John!" as expected.That's why most of the developers (me too) love doing something like this:
"content_scripts": [
{
"matches": ["*://*/*"]
"js": ["jquery.min.js", "script.js"]
}
]
because that's an easy way to include jQuery and use it with your content scripts.
Obviously content scripts will share the same window
object even if they are injected from the background page with the chrome.scripting.executeScript()
(MV3) or chrome.tabs.executeScript()
(MV2) function.
You can easily create a script containing all your utilities and most used functions, so you'll always be ready to use them in any other content script injected after the first one.
So, basically, doing something like this:
"content_scripts": [
{
"matches": ["*://*/*"]
"js": ["script1.js", "script2.js", "script3.js", ...]
}
]
means that:
script1.js
is injectedscript2.js
is injected and inherits the namespace of script1.js
script3.js
is injected and inherits the namespace of script2.js
and script1.js
When the Google documentation says:
Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any functions or access any variables defined by content scripts.
This means that:
But:
In ManifestV3 content scripts can be loaded in the window
of the page by specifying "world": "MAIN"
in their content_scripts
declaration (Chrome 111 and newer) or when injecting/registering via chrome.scripting API (Chrome 95/102 and newer).
Upvotes: 18