动态加载require.js的依赖项

Dynamically load dependencies of require.js

本文关键字:依赖 js 加载 require 动态      更新时间:2023-09-26

我正在使用require.js加载项目的依赖项。类似的东西

var deps = [];
if( some condition )
    deps = [dep1, dep2, ...]
else
    deps = [other1, other2, ...]
define(deps, function(arg1, arg2, ....){
});

这对我来说很好。问题是当我缩小我的代码时,我会遇到以下问题:

Uncaught Error: Mismatched anonymous define() module: function (e,t.....

任何知道解决办法的人都请帮我。提前谢谢。

r.js会检测到要从数组中包含的deps,但如果deps像您的情况一样是动态的,则不会检测到

对于动态deps,您可以配置build.js文件,将其包含在模块中

假设低于代码

main.js

var x = 1;
var deps=[];
if(x > 0){
    deps = ['.'mod1'];
}
else{
    deps = ['.'mod2'];
}
define(deps, function(x){
    return x * 10;
});

mod1.js

define([], function(){
    return 5;
});

mod2.js

define([], function(){
    return 10;
});

r.js不会将mod1和mod2与main一起包含,因为它们不是明确的deps,所以我们必须指示r.js,mod1和mod2可能是main的deps。我们在build.js 中这样做

build.js

({
    paths: {
    },
    shim: {
    },
    baseUrl: "app",
    removeCombined: true,
    findNestedDependencies: true,
    inlineText: true,
    optimizeAllPluginResources: true,
    stubModules: ['text'],
    dir: "app-dist",
    modules: [
        {
            name: "main",
            include: ["mod1","mod2"]
        }
    ]
})

通过此设置,我们指示r.js包括mod1和mod2以及main.js

希望这是明确的

问题

RequireJS的优化器无法对运行时生成的依赖项执行依赖项分析。它至少有能力以镜像运行时发生的事情的方式执行代码,而且仍有无法处理的情况。因此,为了使RequireJS的依赖关系分析成功,您的依赖关系必须是字符串的文本数组。在任何其他情况下,RequireJS都将无法执行分析,并且它将静默地失败。

在你的情况下,这有两个后果:

  1. 优化器实际上并没有为您的模块命名。这就解释了Mismatched anonymous define() module

    优化器的功能之一是为模块提供最终名称。因此,你放在main.js中的一个模块,例如,当它还没有优化时,它会被转换,从而被定义为define("main", ...。优化器将名称添加到define调用的开头。(只有当模块尚未命名时,它才会这样做。)

    如何判断您的模块不是由优化器命名的?除了错误消息(这是一条主要线索)之外,如果您查看r.js生成的内容,您会发现您的模块被定义为define(deps,function。注意模块的第一个参数不是它的名称。

    你还会看到后面的一个存根。这个存根看起来像这个define("main",function(){})。只有当模块的代码不是真正的AMD风格模块时,才应该存在此存根。例如,必须使用shim配置的模块将具有这些存根。但是,您的模块不需要这个存根。

    无论如何,优化器是完全混乱的,并且没有正确地命名您的模块。

  2. 优化器找不到模块的依赖项。

解决方案:调整构建

mfarouk已经提到了如何修改您的构建,以便解决上面的第二个后果。我只想提一下,一般规则是:您必须在模块的include中显式地放入优化器遗漏的所有模块的并集看起来是这样的:

modules: [
    ...,
    {
        name: "mymodule",
        include: [dependency1, dependency2, ...]
    },
    ...
]

其中dependency1等是deps数组中的依赖项。

为了处理第一个后果,您需要额外的定制。我建议使用优化器的onBuildRead选项:

onBuildRead: function (moduleName, path, contents) {
    if (moduleName !== "main")
        return contents;
    return contents.replace(/define'(deps/,
                            'define("' + moduleName + '",deps');
}

当优化器读取每个模块时,会调用此函数。当它读取main时,define调用被修改为添加模块名称。优化器将看到模块已经命名,将保留名称,并且不会生成虚假的存根。