RequireJS 中的动态要求,收到“尚未为上下文加载module名称”错误?

IT技术 javascript browser module requirejs r.js
2021-02-09 06:53:32

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

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

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

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

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

    // ...
});

... 给我:

未捕获的错误:尚未为上下文加载module名称“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
    }

    // ...
});
2个回答

限制与简化的 CommonJS 语法与普通回调语法有关:

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

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,因此使用_.values_.object可以简化上述参数数组的循环。

如果我想添加 - require("somemodule"); 其中 somemodule 是一个 json 文件
2021-03-14 06:53:32
我唯一的问题是:使用的require(_.values(Config), ...)是异步代码,对吗?这意味着我需要在require结束时使用回调样式,对吗?
2021-03-25 06:53:32
请注意,除非您在选项中设置 { findNestedDependencies: true },否则这将破坏 requireJS 的编译功能。
2021-03-28 06:53:32
是的,并且您在答案中使用了回调语法。require(_.values(Config), function () {大致相当于require(dynModules, function(){我的。两者都使用一个字符串数组作为第一个参数,并提供一个回调函数作为第二个参数。
2021-04-02 06:53:32
感谢您的时间,我在 RequireJS 网站上搜索后找到了解决方案。看我的回答。
2021-04-12 06:53:32

回答我自己。从 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...
    });
});
更新了我的答案以澄清。这两个答案都有效,只是想向未来的读者解释 RequireJS 在幕后真正发生的事情。
2021-03-20 06:53:32
不,modules应该在另一个module中定义,即配置文件。顺便说一句,它工作正常。
2021-04-03 06:53:32
看来关键还是CommonJS同步语法到RequireJS回调语法的转换。
2021-04-06 06:53:32
@explunit 你能更好地解释一下你的意思吗?我只需要在 Jade 内部制作一些module(用于浏览器)(作为助手),并且我需要它是动态的。
2021-04-10 06:53:32