开发者

Replace jQuery version of a page with Greasemonkey

开发者 https://www.devze.com 2023-04-11 12:50 出处:网络
How can i replace jquery version of a page with greasemonkey? Im trying to test a site with a newer ve开发者_Go百科rsion of jquery but i dont have a dev enviroment.Making a dev environment, using sou

How can i replace jquery version of a page with greasemonkey?

Im trying to test a site with a newer ve开发者_Go百科rsion of jquery but i dont have a dev enviroment.


Making a dev environment, using source-control and a written release checklist will save you much grief (and is a requirement for most paid work).
~~~

The best way to replace the jQuery version on an existing page (that you don't control) is to:

  1. Stop the page's native jQuery from loading.
  2. Create a <script> node, containing the jQuery version you want, that loads before any subsequent scripts that use jQuery.

Unfortunately, Greasemonkey cannot do #1. It can only tamper with the page's native jQuery after it has loaded -- An approach that might work, but that slows the page and risks race conditions.

So, I recommend a two-tool solution:

  1. Make sure your Firefox has the Adblock add-on (which is an excellent add-on to use irregardless) and/or the RequestPolicy add-on.

  2. Use Adblock or RequestPolicy to temporarily block the old jQuery.
    For example, for StackOverflow, block http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js. (Note that RequestPolicy allows you to limit URL blocking to only a specific site.)

  3. Then use Greasemonkey to load the desired version of jQuery (which it can do irregardless of Adblock or RequestPolicy settings) at the beginning of the page.

    For example, this script will upgrade Meta SO's jQuery to 1.6.2, in conjunction with the block from step 2:

    // ==UserScript==
    // @name            _upgrade jQuery
    // @include         http://meta.stackexchange.com/questions/*
    // @run-at          document-start
    // ==/UserScript==
    
    /*--- Important!
            (1) We need another add-on, besides Greasemonkey, to
                disable the old, undesired script.
            (2) The DOM is not available yet
                (@run-at == document-start).
            (3) We cannot use a loop to check for the DOM because
                loading is halted while the loop runs.
            (4) setTimeout() and setInterval() are not fast enough due
                to minimum interval clamping.  By the time they detect
                the DOM, scripts that we need to precede may have
                loaded.
            (5) Therefor, we use a "set Zero Timeout" function as
                explained by David Baron at
                    http://dbaron.org/log/20100309-faster-timeouts .
            (6) By the time FF reports that the `document.head` is
                available, several head elements have loaded!
                (Is this a bug?)
                That means that if any dependent scripts are loaded
                before we can inject our jQuery version, then we must
                also reload those dependent scripts.
    */
    
    //////  setZeroTimeout() implementation: BEGIN
    
    /*--- Only add setZeroTimeout to the window object, and hide
        everything else in a closure.
    */
    ( function () {
        var timeouts    = [];
        var messageName = "zero-timeout-message";
    
        /*--- Like setTimeout, but only takes a function argument.
            There's no time argument (always zero) and no arguments.
            You have to use a closure.
        */
        function setZeroTimeout(fn) {
            timeouts.push(fn);
            window.postMessage(messageName, "*");
        }
    
        function handleMessage(event) {
            if (event.source == window && event.data == messageName) {
                event.stopPropagation();
                if (timeouts.length > 0) {
                    var fn = timeouts.shift();
                    fn();
                }
            }
        }
    
        window.addEventListener ("message", handleMessage, true);
    
        // Add the one thing we want added to the window object.
        window.setZeroTimeout = setZeroTimeout;
    })();
    
    //////  setZeroTimeout() implementation: END
    
    /*--- Now wait for the DOM and then add our version of jQuery,
        first thing.
    */
    function SearchForDOM () {
    
        var targetNode;
        if (typeof document.head == "undefined")
            targetNode = document.querySelector ("head, body");
        else
            targetNode = document.head;
        if (targetNode) {
    
            var scriptNode      = document.createElement ("script");
            scriptNode.src      = 'http://ajax.googleapis.com/ajax/'
                                + 'libs/jquery/1.6.2/jquery.min.js';
            targetNode.appendChild (scriptNode);
    
            /*--- By the time FF reports that the head element is
                available, a key dependent script has loaded!
                So, we reload it here, so that it can run with jQuery
                available.
            */
            var scriptNode      = document.createElement ("script");
            scriptNode.src      = location.protocol
                                + '\/\/' + location.host
                                + '/content/js/stub.js?v=49f661361016';
            targetNode.appendChild (scriptNode);
        }
        else
            setZeroTimeout (SearchForDOM);
    }
    
    SearchForDOM ();
    


    Note: that due to limitations of JS, GM, and Firefox, it may be necessary to reload scripts that depend on jQuery too. (This is the case for Meta Stack Overflow, at the moment.)


I know you're asking about jQuery and Greasemonkey for doing this, but let me off a completely different alternative, Fiddler.

If you're testing a site out with a new version of jQuery and you actually want to test any breaking changes, etc...you want to test the site as it will be, whereas a JavaScript (greasemonkey)-based after-the-fact replacement isn't an accurate simulation.

With fiddler you can replace the jQuery file that the browser requests (without the browser knowing). This way you're actually testing it completely, you're straight up dropping the new version in the page, no in-page JS tricks which may not be at all accurate to get there (handlers already hooked up, load order, etc.)

Eric Law (creator of Fiddler) has an excellent blog post on how to do exactly this:

Swapping out JQuery with Fiddler

The post was written for swapping out the minified version with the full version (also handy!) or a newer version for debugging, be sure to note both uses...they're both very useful in saving some debug/testing time.


Not sure about Greasemonkey, but an easy approach to modify any resource on (url, image, script) would be using Requestly Redirect Rule.

  1. Open Requesly app from icon (or navigate to http://app.requestly.in/rules)
  2. Click "New Rule"
  3. Select "Redirect Request"
  4. Enter Request source (in your case, "URL""Equals":[url-to-jquery eg: "http://some-host.com/jquery1.4.js"]
  5. Enter Destination (in your case, URL to required jquery version CDN eg: "http://any-host.com/jquery3.2.js")
  6. Click Save
  7. Done! Now all the requests made by your browser to source url will be redirected to your defined destination url.

Note:

  • If you don`t have CDN, you can host the file on web using Requestly Library. Then choose "Select from Library" below Destination URL field.
  • The same results can be achieved using Cancel Request rule to block existing request. Then use Insert Scripts rule to insert your version of script into the webpage.

PS: I work at Requestly.


What didn't work for my case, seems to suit this question, no blocker is required. In GreaseMonkey:

// ==UserScript==
// @name        alternative jquery
// @namespace   ben@host
// @description intercept
// @include     https://somehost.com/*
// @grant       GM_getResourceText
// @resource    jquery_new jquery_new.js
// @run-at      document-start
// @version     1
// ==/UserScript==

var jquery_source = GM_getResourceText( 'jquery_new' );
console.log('jQuery Lenght =',jquery_source.length);

window.addEventListener('beforescriptexecute',  
function(e){
    if (e.target.src &&
        e.target.src.search('/1.12.4/jquery.min.js') >= 0 ) {
            console.log('intercepted: '+e.target.src);
            e.preventDefault();
            e.stopPropagation();
            window.eval(jquery_source);
        }
});

Note: downside - beforescriptexecute fires after the original script is retrieved and ready to be executed, so should the original external js file failed to load, this approach will not work.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号