jquerybrowserifyshimbrowserify-shim

Why doesn't this jquery plugin need a shim in order to work?


Shimming a jQuery plugin appears to be only for geniuses who throw salt over the correct shoulder.

However I did this....

    var backbone = require('backbone');
    global.jQuery = global.$ = backbone.$ = require('jquery');

    require('./libs/jquery-modal');

    $("body").Modal();

and it just works. (n.b. jquery is being loaded via debowerify)

Why does this work? Would shimming it mean I don't need to do the assignments to jquery and $?

And how is browserify able to handle my plugin code not being in the correct commonjs format?


Solution

  • I assume you are talking about the browserify-shim.

    Shimming is used for making commonjs-incompatible files browserifiable.

    To be commonjs-compatible, a file must export something. Here is a simple commonjs module:

    // mystring.js
    module.exports = "Hello Stackoverflow";
    

    Now in some other file, you could require mystring.js and use it like this:

    var str = require('./mystring.js');
    console.log(str); // > "Hello Stackoverflow"
    

    jQuery

    In older versions of jQuery (pre 1.11 and 2.1) nothing was exported. Instead jQuery would attach itself to the window object. That goes against the whole concept of modularity, making your code depend on objects and values to be present in the global scope.

    Loading files in the right order could be tricky in more complex environments. Especially if some config files change some global variables, and your script should be executed when window.foo is set to "bar" but before other script updates window.foo value to "qux".

    When we try to use jQuery before it is loaded, we get a ReferenceError:

    <!-- index.hmtl -->
    <script>
        var $body = $('body'); // ReferenceError: Can't find variable: $
    </script>
    <script src="jquery.js">
    

    That is where browserify-shim comes into play.

    Shim

    In essence browserify-shim does something like this:

    // jquery-shim.js
    loadScript('jquery.js') // now, window.$ contains a reference to the jQuery object
    module.exports = window.$; // exports that jQuery object
    window.$ = null;
    

    Now you can use jQuery anywhere in your code, without relying on it to be present in the global scope:

    <!-- product-page.hmtl -->
    <script> <!-- script is inlined for demo purposes only -->
        var $ = require('./jquery-shim.js');
        var $body = $('body'); // this works now
    </script>
    

    It is about modularizing your project and keeping your global scope clean.