Home » Jquery » How do I use Browserify with external dependencies?

How do I use Browserify with external dependencies?

Posted by: admin November 30, 2017 Leave a comment

Questions:

I am trying to slowly introduce Browserify into my site, but I don’t want to rewrite all the js and I don’t want duplicate instances of jquery and other libraries bundled with my Browserify build.

If I build my module listing jquery as an external dependency, how do I then point it at my global jquery instance? Also the goal is to eliminate the mylibs global (example below), so I don’t want to use it in my module.

This is what I’m trying to do (psudo-code). This would be in my site’s repo – not the module’s. The module would be installed with Bower:

var mylibs.jQuery = $.noConflict(); // global used by lots of existing code
module.exports = {
    jquery: mylibs.jQuery // can be imported by my module as require('jquery')
};

Something like that is what I’m trying to achieve. Is this possible?

Answers:

You can achieve that by using browserify-shim. Assuming that you’ve got a module named mymodule.js that depends on jQuery in the global scope with the following contents:

var $ = require('jQuery');

console.log(typeof $);
  1. Install browserify-shim:

    npm install browserify-shim --save-dev
    
  2. In package.json file, tell browserify to use browserify-shim as a transform:

    {
        "browserify": {
            "transform": [ "browserify-shim" ]
        }
    }
    
  3. In package.json file, tell browserify-shim to map jQuery to the jQuery in the global scope:

    {
        "browserify-shim": {
            "jQuery": "global:jQuery"
        }
    }
    
  4. Run browserify

    browserify mymodule.js > bundle.js
    

If you examine bundle.js you will notice that require('jQuery') is replaced with (window.jQuery).

Questions:
Answers:

Browserify-shim is not transitive across node modules: it can be used to correctly shim top-level (in your own package.json) modules, but it cannot shim modules in other npm packages (with their own package.json files).

This is awkward when dealing with a node module that depends on the jQuery module (eg. a plugin that has a peer dependency), but the jQuery library should still be external.

My solution – similar in concept to the pseudo-code – was to create a custom ‘preload shim’, with the help of browserify itself.

  1. Exclude the jquery module from the generation of bundle.js, but otherwise build the bundle normally.

    Install the appropriate node/npm modules to meet the build requirements. The to-be-excluded “external” modules will not be included in the bundle but are required to fulfill the compilation dependency resolution.

    browserify -x jquery .. > dist/bundle.js
    
  2. Create a file called jquery.js and include this content:

    module.exports = window.jQuery; // or whatever
    
  3. Generate a shim.js including just the previous file.

    browserify -r jquery.js > dist/shim.js
    

    Then edit the file to use jQuery as the module name.

  4. In the browser, load jquery (the external dependency), shim.js, and then bundle.js.

    When the bundle file tries to load the jquery module – which it does not define – it will fallback to the module (previously) defined in the shim file and run the custom code. In this case that’s piping through a previously defined global.

    Or: what browserify-shim “global:” tries to do, only actually .. globally.


Using the browserify module directly – instead of grunt, which I am re-growing to loathe – may have resulted in a ‘more refined’ solution.