63

有没有办法定义一个在 RequireJS 中“动态”加载其他模块的模块?如果是,优化器(r.js)如何理解必须包含模块的方式/时间?

例如,让dynModules一个定义名称/路径对的模块:

define([], function () {
    return ['moduleA', 'moduleB']; // Array of module names
});

另一个模块将根据数组动态加载模块。这不起作用

define(['dyn_modules'], function (dynModules) {
    for(name in dynModules) {   
        var module = require(path); // Call RequireJS require
    }

    // ...
});

... 给我:

未捕获的错误:尚未为上下文加载模块名称“moduleA”:_。使用 require([]) http://requirejs.org/docs/errors.html#notloaded

我可以解决错误,但它不再是“动态的”:

define(['dyn_modules', 'moduleA', 'moduleB'], function (dynModules) {
    for(name in dynModules) {   
        var module = require(path); // Call RequireJS require
    }

    // ...
});
4

2 回答 2

74

限制与简化的 CommonJS 语法与正常的回调语法有关:

由于下载模块的时间未知,加载模块本质上是一个异步过程。但是,RequireJS 在模拟服务器端 CommonJS 规范时试图为您提供简化的语法。当你做这样的事情时:

var foomodule = require('foo');
// do something with fooModule

幕后发生的事情是 RequireJS 正在查看您的函数代码的主体并解析出您需要 'foo' 并在您的函数执行之前加载它。但是,当变量或简单字符串以外的任何内容时,例如您的示例...

var module = require(path); // Call RequireJS require

...然后 Require 无法解析并自动转换它。解决方法是转换为回调语法;

var moduleName = 'foo';
require([moduleName], function(fooModule){
    // do something with fooModule
})

鉴于上述情况,这是您的第二个示例的一种可能的重写以使用标准语法:

define(['dyn_modules'], function (dynModules) {
    require(dynModules, function(){
        // use arguments since you don't know how many modules you're getting in the callback
        for (var i = 0; i < arguments.length; i++){
            var mymodule = arguments[i];
            // do something with mymodule...
        }
    });

});

编辑:根据您自己的回答,我看到您正在使用下划线/lodash,因此使用_.valuesand_.object可以简化上述参数数组的循环。

于 2013-07-03T13:05:18.013 回答
7

回答我自己。从 RequireJS 网站:

//THIS WILL FAIL
define(['require'], function (require) {
    var namedModule = require('name');
});

这会失败,因为 requirejs 需要确保在调用上面的工厂函数之前加载并执行所有依赖项。[...] 因此,要么不传入依赖数组,要么如果使用依赖数组,请列出其中的所有依赖项。

我的解决方案:

// Modules configuration (modules that will be used as Jade helpers)
define(function () {
    return {
        'moment':   'path/to/moment',
        'filesize': 'path/to/filesize',
        '_':        'path/to/lodash',
        '_s':       'path/to/underscore.string'
    };
});

装载机:

define(['jade', 'lodash', 'config'], function (Jade, _, Config) {
    var deps;

    // Dynamic require
    require(_.values(Config), function () {
        deps = _.object(_.keys(Config), arguments);

        // Use deps...
    });
});
于 2013-07-03T13:06:29.900 回答