Loading multiple instances of requireJS and Backbo

2019-03-04 14:09发布

问题:

I am creating a google chrome extension which, when activated on a tab, loads some custom code and a few new views into the document of that window. I'd like to use requireJS to load these new modules of code called by the extension. However, I worried about a possible conflict or name collision that might occur if the app/website this extension is called on is already running requireJS, and my calling it from scratch either wipes the sites native require.config or otherwise causes some unknown mischief. This would cause the site to break every time my extension is activated on it.

So is there a way to load entirely new and "independent" instances of requireJS and backboneJS onto a site that MAY already have its own instances running? If not, is there a way to reconcile my requirements and configs with those of the target app?

EDIT W/ MORE DETAILS: Ok, so a little more detail on my extension: I am creating an iFrame on the page, which has a completely unique document space. But I still need the iFrame to be aware of certain things going on in the original document (ex: when the user clicks on a certain div in that document, I want this event to be passed to the iFrame). To do this, I pass various objects through the original document's content script, up to the extension, back to the iframe's content script, and then finally (using window.onMessage), on to the iFrame's javascript environment. The process I've developed is roughly similar to the one described here. And yes, it makes my head hurt.

Anyway, the point of all that is that I have a LOT of code going on in the iframe, the extension, and the original source document. So, I'd like to have a require instance in each of these contexts.

回答1:

Content scripts run in a context that is isolated from the page's context. I.e. if the page declares a global variable Backbone, your content script cannot directly read or access it.

Drop the following code (just written) in your Chrome extension (put it after require.js), and you will be able to use RequireJS in your content scripts.

require.load = function(context, moduleName, url) {
    url = chrome.extension.getURL(url);
    var x = new XMLHttpRequest();
    // Append Math.random()... to bust the cache
    x.open('GET', url + '?' + Math.random().toString(36).slice(-4));
    x.onload = function() {
        var code = x.responseText;
        x += '\n//@ sourceURL=' + url; // Optional, for debugging.
        window.eval(code);
        context.completeLoad(moduleName);
    };
    x.onerror = function() {
        // Log error if you wish. This is usually not needed, because
        // Chrome's developer tools does already log "404 Not found"
        // errors for scripts to the console.
    };
    x.send();
};

During development, this method is quite ideal, because the line numbers will match the lines in your code.

In production, I suggest to use r.js to concatenate (and minify) your code, because the output will be one big JavaScript file. Resources within a Chrome extension are typically loaded within a few milliseconds, but if you have quite a lot of modules, these milliseconds will add up to something significant. And each request is visible in the Network tab in the developer tools for the given tab, which is just noise, and an undesired side-effect for web developers who use your extension.