为啥简化的 CommonJS Wrapper 语法不适用于我的 Dojo AMD 模块?

Posted

技术标签:

【中文标题】为啥简化的 CommonJS Wrapper 语法不适用于我的 Dojo AMD 模块?【英文标题】: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=truedebugAtAllCosts 不会再抛出任何东西。适合您的变化是什么? 我无法在 JSFiddle 上分成多个文件,所以我尝试了 define("foo", function (require) ... ),其中 ... 包含您的要求语句,加上 console.logs 用于 fxdom 对象。控制台记录了两个看起来很疯狂的对象... Dojo 1.7.1? 嗯...除了 _base 中的几个模块之外,我似乎什么都没有加载。 dojo/_base/kerneldojo/_base/array 工作,但我尝试过许多其他的抛出 undefinedModule 错误。这是路径问题吗?我尽可能多地关注 T 的参考资料,但它不起作用。 此外,使用第一个“name”参数(在您的示例中为 foo),则结果对象为 3,因此没有属性。没有那个参数,我至少可以访问exports 【参考方案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)

【讨论】:

以上是关于为啥简化的 CommonJS Wrapper 语法不适用于我的 Dojo AMD 模块?的主要内容,如果未能解决你的问题,请参考以下文章

javascript CommonJS`require`语法用于使用React lazy

用于导入 commonjs / amd 模块的新 es6 语法,即 `import foo = require('foo')`

模块化 angularjs 应用程序 commonJS 与 AMD 模块语法

导入 3rd 方库时的 CommonJS 汇总插件语法错误,主要与“进程”有关

为啥使用 ia-wrapper 将后续项目上传到 archive.org 时仍然存在陈旧的标头值?

amd cmd commonjs 模块规范 和 es6 的 module 语法