N-ate
N-ate

Reputation: 6926

web_accessible_resources can't access chrome.tabs.executeScript

I'm developing an extension that uses chrome.tabs.executeScript to load an instance of requirejs from a file that has been placed in a closure to prevent it from polluting the global space. Let's call this closure __MyGlobal. This executes as expected.

I then use chrome.tabs.executeScript to run code in the same tab. This code is a basic __MyGlobal.require([dependencies],function(){}) call. This executes as expected.

It is the dependencies of that Require call that fail on their __MyGlobal.declare() calls.

The error is Uncaught ReferenceError: __MyGlobal is not defined.


Testing further if I enter __MyGlobal in the console it is not defined. If I change the domain to my extension then the console shows __MyGlobal as expected.

enter image description here

I'm not sure how

In short

  1. chrome.tabs.executeScript loads require.js
  2. chrome.tabs.executeScript loads a require() statement with dependencies
  3. require() file dependencies load (they're declared in web_accessible_resources)
  4. require() dependencies had dependencies of their own (define statements)
  5. the define statements cannot access requirejs

How can I get code loaded with chrome.tabs.executeScript and loaded as web_accessible_resources to play nice together? Are they in different domains? Thanks!

Upvotes: 0

Views: 377

Answers (1)

N-ate
N-ate

Reputation: 6926

Scripts injected with chrome.tabs.executeScript are "Content Scripts", meaning they are executed in their own javascript environment different than that of the website. They interact with the same DOM as the website.

requirejs works by creating script tags to load dependencies. Therefore the scripts loaded by requirejs are loaded into the page's javascript environment and not the extension's javascript environment.

You can read more about the way chrome extension environments are separated here. Programmatic-Injection and Execution-Environment are both worth a read if your doing more than the most basic development for chrome.

The following sample, credit due to wOxxOm (source here), can be added at the bottom of the require.js file to get requirejs to load via ajax when requirejs is running in its own javascript environment as a content script.

var legacyLoad = requirejs.load;
requirejs.load = function(context, moduleName, url){
    if(location.protocol === 'chrome-extension:'){//works for extension pages
        legacyLoad(context, moduleName, url);        
    }
    else {//works for content scripts
        var x = new XMLHttpRequest();
        x.open('GET', url);
        x.onload = function() {
            if (x.status === 200) {
                // Run script in the current global context.
                try {
                    window.eval(x.responseText);
                } 
                finally {
                    context.completeLoad(moduleName);
                }
            } 
            else context.onScriptError(new Event('error'));

        };
        x.onerror = function() {
            ontext.onScriptError(new Event('error'));
        };
        x.send();
    }
}

Upvotes: 1

Related Questions