Replace jQuery version of a page with Greasemonkey

后端 未结 4 1536
鱼传尺愫
鱼传尺愫 2020-12-24 10:20

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

Im trying to test a site with a newer version of jquery but i dont have a dev enviroment.

相关标签:
4条回答
  • 2020-12-24 10:25

    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.)

    0 讨论(0)
  • 2020-12-24 10:33

    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.

    0 讨论(0)
  • 2020-12-24 10:37

    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.

    0 讨论(0)
  • 2020-12-24 10:50

    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 讨论(0)
提交回复
热议问题