require jQuery to a safe variable in Tampermonkey script and console require jQuery to a safe variable in Tampermonkey script and console google-chrome google-chrome

require jQuery to a safe variable in Tampermonkey script and console


Apart from avoiding version conflicts and breaking the content page, I do a handful of other things in my default userscript template that includes jQuery.

The template below strives to meet the following goals in the interest of being a universal template for including jQuery in new scripts regardless of the content page's current or future status with regards to it's own inclusion, or lack thereof, of jQuery of any version.

  • avoid security sandbox with @grant none
  • in general remain agnostic about where script is inserted/when its executed
  • include specific version of jQuery for our UserScript
  • Preserve the content page's $ and jQuery references to whatever they may be, jQuery or not.
  • Allow our script to use the $ alias for its jQuery version

The use of @grant none is key here

//@grant          none

@grant none works for 99% of my scripts. It allows easy access to the content page's variables, functions, and objects by maintaining a global scope for the UserScript(this), and providing unqualified access to the content page's global scope(window) by searching both scopes for variable, function identifiers in this, window order. So if you avoid duplicating identifiers that exist in the content page, you can access content page variables, functions, and function return values without qualifying ("this." or "window."). And you can do so from anywhere in your script.

This highlights the OP's orignal issue. The convenience that @grant none provides is also the reason the @require directive overwrites the window's $ and jQuery references when it loads. The jQuery library has included the noConflict() function for quite some time to handle just this issue.

We can do some quick improvements right away to the answer above to increase our safety/compatibility/reuse.

window.jQ = $.noConflict(true);
  • This call doesn't explicitly qualify the $ to a scope
  • And it will not work particularly well if the content page also includes some other library that has aliased $. Especially if the content page has already called the jQuery noConflict itself before we get here. This is an unnecessary rabbit hole to get caught in.
  • This code somewhat alarmingly places the reference to our library in the window's scope where it could very well be altered by the content page in some way later. It is generally bad practice to expose anything to the window scope for obvious reasons.

This code instead

this.$ = window.jQuery.noConflict(true);
  • Keeps our library in our scope where it belongs
  • gives us the $ alias in our scope to continue using in our script
  • restores the window's $ and jQuery aliases to what the were when our jQuery loaded whether they were actually jQuery or not
  • gives us the best chance to be using the jQuery object loaded by the script to call noConflict

That last point is probably overkill, but why not be explicit and use the jQuery identifier to make the noConflict call. While it would be our fault at this point if $ wasn't jQuery when this call runs (@require for another library that uses $, using it yourself before this code runs, etc,) it's free prevention of later debugging effort.

While we could be done and happy there, we can also go a bit further to ensure compatibility across the widest variety of pages, and through the largest variety of content page changes.

(function ($, undefined) {  $(function () {    //Your code here;  });})(window.jQuery.noConflict(true));

While still not guaranteed, this pattern gives your functional code the best chance to execute in the largest variety of page lifecyle possibilities by keeping the $ alias out of the global scope and leveraging jQuery's DOM Ready event to ensure page completion. As an aside it also ensures a consistent undefined value for your code.

// ==UserScript==// @name          jQuery safe inclusion template// @description   include jQuery and make sure window.$ is the content page's jQuery version, and this.$ is our jQuery version.// @version       0.0.1// @author        Sonic Beard// @match         http://*.site.com/*// @require       http://cdn.jsdelivr.net/jquery/2.1.3/jquery.min.js// @grant         none// ==/UserScript==(function ($, undefined) {  $(function () {    //Your code here;  });})(window.jQuery.noConflict(true));


TamperMonkey does not appear to have such functionality, but an alternative would be to immediately call $.noConflict with the removeAll argument set to true. This will cause jQuery to reset the original $ and jQuery back to their original values.

Example UserScript:

// ==UserScript==// @name         jQuery noConflict test// @namespace    http://example.com/// @version      0.1// @description  test jQuery noConflict// @author       You// @match        https://steamcommunity.com/// @require      https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js// @grant        none// ==/UserScript==window.jQ = $.noConflict(true);

And you can see from the example console input below, jQ is the jQuery 2.1.3 that was loaded by @require, jQuery is the version of jQuery the page loads, and $ is still the original prototype library object, as evidenced by not having jQuery's fn property.

Example Console Input/Output:

> jQ.fn.jquery< "2.1.3"> jQuery.fn.jquery< "1.11.1"> $.fn< undefined