Search code examples
javascriptgoogle-chromecross-browsergreasemonkeyuserscripts

window.onload works in Firefox+Greasemonkey script but not in a Chrome userscript?


There is a page http://example.com/1.php that includes javascript file as usual:

<script type="text/javascript" src="/util.js?1354729400"></script>

This file contain function named exampleFunction which I need to use in my userscript. Also I have an user script:

// ==UserScript==
// @name          SomeName
// @namespace     http://example.com/userscripts
// @description   Greets the world
// @include       http://example.com/*
// ==/UserScript==
window.onload = function () {
        console.log(exampleFunction);
      alert("LOADED!");
}

which works perfectly in Firefox and returns an error in Chrome:

Uncaught ReferenceError: exampleFunction is not defined 

How do I make it work?


Solution

  • The reason that exampleFunction was undefined is because Chrome userscripts operate in a sandbox ("isolated world"). Note that Greasemonkey scripts often operate in a sandbox too, but yours is currently running with an implicit @grant none.
    If your script were to use a GM_ function, it would stop working in Firefox too.

    To make this script work on both browsers (and a few others, as well), use Script Injection similar to this answer.

    However, there is another hitch, since that script is using window.onload. Chrome userscripts, with the default execution start-mode, will often never see the onload event.

    To get around that, add // @run-at document-end to the metadata block.

    So the script becomes:

    // ==UserScript==
    // @name            SomeName
    // @namespace       http://example.com/userscripts
    // @description     Greets the world
    // @include         http://example.com/*
    // @run-at          document-end
    // @grant           none
    // ==/UserScript==
    
    function GM_main () {
        window.onload = function () {
            console.log(exampleFunction);
            alert("LOADED!");
        }
    }
    
    addJS_Node (null, null, GM_main);
    
    //-- This is a standard-ish utility function:
    function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
        var D                                   = document;
        var scriptNode                          = D.createElement ('script');
        if (runOnLoad) {
            scriptNode.addEventListener ("load", runOnLoad, false);
        }
        scriptNode.type                         = "text/javascript";
        if (text)       scriptNode.textContent  = text;
        if (s_URL)      scriptNode.src          = s_URL;
        if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';
    
        var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
        targ.appendChild (scriptNode);
    }