How do I use Browserify with external dependencies?

Solution 1:

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

Solution 2:

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.