【问题标题】:Why is the Simplified CommonJS Wrapper syntax not working on my Dojo AMD module?为什么简化的 CommonJS Wrapper 语法不适用于我的 Dojo AMD 模块?
【发布时间】:2012-02-09 08:58:51
【问题描述】:

我开始考虑 requirejs 和新的 Dojo AMD 结构,但我在一些早期测试中遇到了问题:

cg/signup.js:

define(['dojo/_base/fx', 'dojo/dom'], function(fx, dom){    
    return function(){
        this.hidePreloader = function(id){
            var preloader = dom.byId(id);
            fx.fadeOut({node : preloader}).play()
        }
    }
})

这很好用。在主 cg.js 文件中:

require(['dojo/_base/kernel', 'dojo/_base/loader'])
dojo.registerModulePath('cg', '../cg')

require(['cg/signup', 'dojo/domReady!'], function(Signup){
        var sp = new Signup();
        sp.hidePreloader('preloader')
})

巴姆。完毕。但是,在使用 Simplified CommonJS Wrapper 结构时:

define(function(require){    
    var fx = require('dojo/_base/fx'),
        dom = require('dojo/dom');

    return function(){
        this.hidePreloader = function(id){
            var preloader = dom.byId(id);
            fx.fadeOut({node : preloader}).play()
        }
    }
})

我收到一个 undefinedModule 错误。它似乎来自dojo/_base/fx 行,但我不知道为什么。

更新

为了澄清。

index.html 脚本

<script type="text/javascript" src="js/dojo/dojo.js.uncompressed.js" data-dojo-config="isDebug:true,async:true"></script>
<script type="text/javascript" src="js/cg.js"></script>

cg.js

require(['dojo/_base/kernel', 'dojo/_base/loader'])
dojo.registerModulePath('cg', '../cg')

require(['cg/signup', 'dojo/domReady!'], function(signup){
    signup.testFunc()
})

js/cg/signup.js

define(['require', 'exports'], function(require, exports){
    var dom = require('dojo/_base/kernel');
// Any other require() declarations (with very very few exceptions like 'dojo/_base/array throw undefinedModule errors!!!

    // without any error causing requires, this works fine.
    exports.testFunc = function(){
        alert("hello")
    }
})

【问题讨论】:

  • 嗯,稍微不同的变体似乎适用于 JSFiddle。 (但我现在无法链接到它,因为 JSFiddle 处于只读模式。)您能否提供有关确切错误的更多详细信息?
  • 这就是确切的错误。通过使用具有相同路径和相同 require 语句的 Simplified CommonJS Wrapper 技术,控制台会打印错误 undefinedModule。我在脚本配置中有isDebug=true,debugAtAllCosts 不会再抛出任何东西。适合您的变化是什么?
  • 我无法在 JSFiddle 上分成多个文件,所以我尝试了 define("foo", function (require) { ... }),其中 ... 包含您的要求语句,加上 console.logs 用于 fx 和 dom 对象。控制台记录了两个看起来很疯狂的对象... Dojo 1.7.1?
  • 嗯...除了 _base 中的几个模块之外,我似乎什么都没有加载。 dojo/_base/kernel 和 dojo/_base/array 工作,但我尝试过许多其他的抛出 undefinedModule 错误。这是路径问题吗?我尽可能多地关注 T 的参考资料,但它不起作用。
  • 此外,使用第一个“name”参数(在您的示例中为 foo),则结果对象为 3,因此没有属性。没有那个参数,我至少可以访问exports。

标签: javascript dojo js-amd


【解决方案1】:

dojo 完全支持 Simplified CommonJS Wrapper 格式。但是,有一个先决条件...您必须没有依赖项数组。

define(function (require, exports, module) {
    var fx = require('dojo/_base/fx'),
        dom = require('dojo/dom');

    // continue...
});

这将不一样

define(['require', 'exports', 'module'], function (require, exports, module) {
    var fx = require('dojo/_base/fx'),
        dom = require('dojo/dom');

    // continue...
});

这也不会……

// in this case require, exports and module will not even exist
define([], function (require, exports, module) {
        var fx = require('dojo/_base/fx'),
        dom = require('dojo/dom');

    // continue...
});

【讨论】:

  • 感谢您对本次对话的补充,我将不得不打开该项目备份并进行更多测试。这是一个有趣的警告,你知道为什么吗?
  • 这样做是因为要支持这种格式,需要扫描函数体以查找require(...) 的用法,这会增加一些开销。为了避免不需要的开销,您需要使用这种格式向加载程序“发出信号”(或不取决于您的观点)。您使用这种格式的“信号”没有依赖项数组 - 这就是为什么一个空的依赖项数组与根本没有依赖项数组不同。
  • 我在dojo 1.8.3中尝试了这个简单的例子,但它根本不起作用。
  • 您是从源代码还是从构建/CDN 使用 dojo?默认的构建选项会去掉支持这个的代码。
【解决方案2】:

这里是 Dojo 定义的一个小包装器,它使用来自 RequireJS 的代码根据定义函数的 toString 计算依赖关系。它将当前的“define”包装在全局命名空间中,计算依赖关系,然后调用包装好的define。

defineWrapper.js:

// Workaround for the fact that Dojo AMD does not support the Simplified CommonJS Wrapper module definition
(function() {
    var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
      cjsRequireRegExp = /require\(\s*["']([^'"\s]+)["']\s*\)/g,
      ostring = Object.prototype.toString;
    function isArray(it) {
      return ostring.call(it) === '[object Array]';
    }
    function isFunction(it) {
      return ostring.call(it) === '[object Function]';
    }
    var oldDefine = define;

    define = function(name, deps, callback) {
        //Allow for anonymous functions
        if (typeof name !== 'string') {
          //Adjust args appropriately
          callback = deps;
          deps = name;
          name = null;
        }

        //This module may not have dependencies
        if (!isArray(deps)) {
          callback = deps;
          deps = [];
        }

        //If no name, and callback is a function, then figure out if it a
        //CommonJS thing with dependencies.
        if (!deps.length && isFunction(callback)) {
          //Remove comments from the callback string,
          //look for require calls, and pull them into the dependencies,
          //but only if there are function args.
          if (callback.length) {
              callback
                  .toString()
                  .replace(commentRegExp, '')
                  .replace(cjsRequireRegExp, function(match, dep) {
                      deps.push(dep);
                  });

              //May be a CommonJS thing even without require calls, but still
              //could use exports, and module. Avoid doing exports and module
              //work though if it just needs require.
              //REQUIRES the function to expect the CommonJS variables in the
              //order listed below.
              deps = (callback.length === 1 ? ['require'] :
                  ['require', 'exports', 'module']).concat(deps);
          }
        }

        if(name === null) {
            return oldDefine(deps, callback);
        } else {
            return oldDefine(name, deps, callback);
        }
    }
})();

你会如何使用它?

<script src="...dojo..."></script>
<script src="defineWrapper.js"></script>
<script>require(["some_simplified_commonjs_defined_module"], function(module) {
   // use module here
});</script>

【讨论】:

    【解决方案3】:

    请注意,Dojo 不支持在构建时使用简化的 CommonJS 样式进行依赖检测。这意味着您要么需要使用正常的依赖列表样式,要么在构建配置文件中定义层时必须复制所有依赖项。

    这是他们跟踪器中的相关错误:

    http://bugs.dojotoolkit.org/ticket/15350

    【讨论】:

    • 从 dojo 1.9.0 开始,现在构建支持此功能
    【解决方案4】:

    require 是否已定义?我看不出那个参数值来自哪里。我想你可能不得不做类似的事情

    define(["require"], function(require){ ...
    

    【讨论】:

    • 不,它适用于dojo/_base/kernel,但不适用于dojo/_base/fx,因此定义了require。
    【解决方案5】:

    我开始想,也许我不适合学习 Dojo。但是,这一切都伴随着更多的阅读。我不确定我到底做了什么不同或其他什么,但这是工作布局。

    index.html 脚本和配置

    <script type="text/javascript">
    dojoConfig = {
        async : true,
        isDebug : true,
        debugAtAllCosts : true,
        packages : [{
            name : 'cg',
            location : '/../js/cg'
        }]
    }
    </script>
    <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojo/dojo.js"></script>
    <script type="text/javascript" src="js/cg.js"></script>
    

    js/cg.js

    require(['cg/signup', 'dojo/ready'], function(signup){
        signup.init('preloader')
    })
    

    js/cg/signup.js

    define(['dojo', 'require'], function(dojo, require){
        var fx = require('dojo/_base/fx')
    
        return new function(){    
            this.init = function(id){
                fx.fadeOut({node : dojo.byId(id)}).play()
            }
        }
    })
    

    同样,不完全确定为什么var fx = require(...) 语句在这个语句中的工作方式与其他语句不同,可能是我下载的构建版本与 CDN 的区别,谁在乎呢。有用。我用来帮助其他人的一些链接可能在同一条船上:

    Writing Modular JS

    AMD vs CommonJS Wrapper

    Dojo Toolkit AMD

    Dojo Config (1.7)

    【讨论】:

      猜你喜欢
      • 2015-09-07
      • 2023-03-11
      • 2015-04-22
      • 1970-01-01
      • 1970-01-01
      • 2019-09-30
      • 2013-06-10
      • 2018-11-22
      相关资源
      最近更新 更多