Browserify with jQuery >= 2 produces "jQuery requires a window with a document"

browserify, commonjs, javascript, jquery

Solution

TL;DR;

In your case, it should be as simple as using;

$ = require('jquery/dist/jquery')(window);  // v2.1.0-beta2  

It might be obvious; but you'll have to use this form of declaration (pass `window` to the result of `require`) in every module you use, not just one/ the first, etc.

Non-TL;DR;

For anyone wanting to know why, the interesting code in jQuery which handles this is;

(function( window, factory ) {

    if ( typeof module === "object" && typeof module.exports === "object" ) {
        // Expose a jQuery-making factory as module.exports in loaders that implement the Node
        // module pattern (including browserify).
        // This accentuates the need for a real window in the environment
        // e.g. var jQuery = require("jquery")(window);
        module.exports = function( w ) {
            w = w || window;
            if ( !w.document ) {
                throw new Error("jQuery requires a window with a document");
            }
            return factory( w );
        };
    } else {
        factory( window );
    }

// Pass this, window may not be defined yet
}(this, function( window ) {

    // All of jQuery gets defined here, and attached to the (locally named variable) "window".

}));

Note the comments at the top which explicitly address browserify; in situations where jQuery is in CommonJs-land, instead of returning `jQuery` as we know it, it returns a function which, when passed an object (which should be `window`), returns jQuery.

To confuse the matter further, this setup code has changed again in the latest commit, so that `module.exports` is determined like so;

module.exports = global.document ?
    factory( global ) :
    function( w ) {
        if ( !w.document ) {
            throw new Error( "jQuery requires a window with a document" );
        }

        return factory( w );

... such that if `this` is the `window` object when jQuery is `require()`'d, it will return a jQuery instance, or if not it'll return the factory function as before; so when 2.1.0 actually gets released, you'll have to remove the `(window)` call again.

Problem

I'm using browserify to bundle my front-end javascript using CommonJS-style dependencies. For example, I have: ``` $ = require('jquery/dist/jquery'); // v2.1.0-beta2 _ = require('underscore'); Backbone = require('backbone'); ``` However, when browserify bundles the dependencies I run into the following console error: ``` Error: jQuery requires a window with a document ``` Looking at the jQuery code, I see it's trying to use `this` for the global `window`. ``` (function( window, factory ) { .... }(this, function( window ) { ``` Since browserify wraps all dependencies, `this` is an `object`, not the `window`. What's interesting is jQuery >= 2 should be CommonJS compatible. However, the problem is how browserify wraps the dependencies. Has anyone solved this problem?

Original source