Chrome extensions are one of those toys which once you learn to develop it’s hard to stop. I’ve written a bunch of small improvements to various sites I visit on a regular basis, usually simple changes, but one recent endeavour had me scratching my head for a bit.
Isolated worlds do not allow for content scripts, the extension, and the web page to access any variables or functions created by the others. This also gives content scripts the ability to enable functionality that should not be accessible to the web page.
There is a simple way to circumvent this if your extension requires it, while it is a little crude it gets the job done. Let’s start with a rather contrived but simple example.
data, and a function called
logHelloWorld that writes “Hello World” to the console. Let’s say that our extension needs to access both of these, we want to write the data variable content to the page so it’s visible, and we want to execute the function.
We may write something like the following in our content script.
// dumping data to the page h2 = document.createElement('h2') h2.innerText = data // referencing the data variable defined in the page document.getElementById('content').appendChild(h2) // executing logHelloWorld logHelloWorld() // referencing the logHelloWorld defined in the page
If we paste the above code into the Chrome developer console it works as expected. The
data string is appended to the
content div, and the logHelloWorld function writes to the console.
However, putting the same code into an extension content script results in a terminating error.
This is due to the Isolated World execution environment - our extension does not have access to functions and variables defined in the page.
Injecting script tags into the DOM
The way we can circumvent this is instead of having our content script execute in its special environment, we append our code to the DOM inside a
<script> tag which will cause the browser to run it within the context of the page, giving it access all page variables and functions.
Let’s try the following.
const injectedCode = ` h2 = document.createElement('h2') h2.innerText = data document.getElementById('content').appendChild(h2) logHelloWorld() ` var script = document.createElement("script"); script.textContent = injectedCode; (document.head).appendChild(script);
This once again gives us the result we want!