Boris Ablamunits
Boris Ablamunits

Reputation: 115

Executing a script in the current tab, from within a popup

So after being properly educated in this thread and moving a little bit further with developing Chrome Extensions, it seems that I need more direction on how to move forward.

function testFunction() {
    chrome.tabs.query({active: true, currentWindow: true}, function(arrayOfTabs) {
    var activeTab = arrayOfTabs[0];
    chrome.tabs.executeScript(activeTab.id, {file: "test.js"});
});

The test.js contains my script. It works fine when messing around with basic things like console.log and changing background colors, but does not seem to work for the pre-made script Im trying to use. Like I mentioned in my previous thread, the script I have works well when I simply paste it in the console - and I want the extension to do just that. I was probably wrong at first when I said that the script does not depend on anything on the page.

What exactly is happening when running code via the console, and how can I run the same code via an extension?

Thanks.

Upvotes: 1

Views: 2293

Answers (1)

Xan
Xan

Reputation: 77523

Your code works differently in the console and in the content script, because Chrome creates a separate, isolated JavaScript context for each extension's scripts.

There are many reasons for it, not least security: the page cannot affect a script running in the higher-privilege extension context. Also, it means that there are no clashes between code used by the page and the script. For more information, see the link above.


When you execute code in the console, you can notice a drop-down above the console, which by default reads <top frame>. This is where you select which context to execute commands in. If there is a context script injected from any extension, you will see its context there too.

The script you mention refers to the JavaScript objects already defined on the page; this is why it works if you execute it in the console by default, but when called from a context script those objects do not exist.


So, are those completely isolated? Both contexts have shared access to DOM. This enables content scripts to inject code into the page's context: you can create a <script> element and insert it into the page. This will execute the code in the page's context.

For the canonical question covering this topic, see Inject code in a page using a Content script. This is barely mentioned at all in the official documentation and frankly blew my mind the first time I saw it's possible.

So, in your case, you need a content script that acts like a proxy, injecting a page-level script:

// content.js - this is what you pass to `executeScript`
var s = document.createElement('script');
s.src = chrome.runtime.getURL('test.js'); // This is the actual script
s.onload = function() {
    this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);

For this to work, you need to add test.js to web-accessible resources in the manifest (since the webpage itself will request to load it when you add that <script> tag):

  "web_accessible_resources" : [ "test.js" ],

Upvotes: 3

Related Questions