【问题标题】:Browserify with jQuery >= 2 produces "jQuery requires a window with a document"Browserify with jQuery >= 2 产生“jQuery 需要一个带有文档的窗口”
【发布时间】:2013-12-21 06:28:14
【问题描述】:

我正在使用 browserify 使用 CommonJS 样式的依赖项来捆绑我的前端 javascript。例如,我有:

$ = require('jquery/dist/jquery');  // v2.1.0-beta2                                                                                                                                                                       
_ = require('underscore');                                                                                                                                                                                 
Backbone = require('backbone');

但是,当 browserify 捆绑依赖项时,我遇到以下控制台错误:

Error: jQuery requires a window with a document

查看 jQuery 代码,我发现它正在尝试将 this 用于全局 window

(function( window, factory ) {
....
}(this, function( window ) {

由于 browserify 包装了所有依赖项,thisobject,而不是 window

有趣的是 jQuery >= 2 应该是 CommonJS 兼容的。但是,问题在于 browserify 如何包装依赖项。有人解决了这个问题吗?

【问题讨论】:

    标签: javascript jquery commonjs browserify


    【解决方案1】:

    我也可以像 Johnny Zhao 那样包含它 - 但需要先包含 jsdom。

    我安装了 jquery 和 jsdom 版本: jquery@2.2.0 node_modules\jquery jsdom@7.2.2 node_modules\jsdom

    然后跑:

    var jsdom = require("jsdom");
    var $ = require('jquery')(jsdom.jsdom().defaultView);
    
    $("<h1>test passes</h1>").appendTo("body");
    console.log($("body").html());
    

    【讨论】:

      【解决方案2】:

      如果你使用的是最新版本(6.x)的jsdom和最新版本的jquery(2.1.4),你可以这样做:

      var $ = require('jquery')(jsdom.jsdom().defaultView);
      

      【讨论】:

        【解决方案3】:

        上面的 CreateWindow() 解决方案对我不起作用。

        但是,以下允许我在节点中获取最新版本的 JQuery:

        var $ = require('jquery')(require("jsdom").jsdom().parentWindow);
        

        【讨论】:

        • parentWindow 但不是 CreatWindow() 适合我。谢谢!
        【解决方案4】:
        var $ = require('./node_modules/jquery');
        

        //替换来源

        var jsdom = require("./node_modules/jsdom");
        var window = jsdom.jsdom().createWindow();
        var $ = require('./node_modules/jquery/dist/jquery')(window);
        

        【讨论】:

          【解决方案5】:

          TL;DR;

          在你的情况下,它应该像使用一样简单;

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

          这可能很明显;但是您必须在您使用的每个模块中使用这种形式的声明(将window 传递给require 的结果),而不仅仅是一个/第一个等。


          非 TL;DR;

          对于任何想知道为什么的人来说,处理这个问题的 jQuery 中有趣的代码是;

          (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".
          
          }));
          

          注意顶部的 cmets 显式地址 browserify;在 jQuery 在 CommonJs-land 中的情况下,它不是返回我们所知道的 jQuery,而是返回一个函数,当传递一个对象(应该是 window)时,它返回 jQuery。


          为了进一步混淆问题,此设置代码在最新提交中再次更改,因此module.exportsdetermined 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 );
          

          ... 这样如果this jQuery 为require()'d 时的window 对象,它将返回一个jQuery 实例,否则它将返回工厂功能和以前一样;因此,当 2.1.0 实际上 发布时,您将不得不再次删除 (window) 调用。

          【讨论】:

          • 很好的答案,谢谢。对于那些正在寻找的人,请注意,即使使用 jQuery >=2,您仍然必须在 Backbone = require('backbone'); 之后使用 Backbone.$ = $;
          • 我遇到了类似的问题,经过一番阅读,这里 => gist.github.com/gabeno/8950573 是我的解决方案。
          猜你喜欢
          • 2017-08-29
          • 2014-02-16
          • 1970-01-01
          • 1970-01-01
          • 2017-10-22
          • 2019-10-21
          • 2018-07-05
          • 2020-08-19
          • 1970-01-01
          相关资源
          最近更新 更多