简体   繁体   中英

Dynamically load dependencies of require.js

I am using require.js to load my dependencies on a project. Something like

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

});

This is working fine for me. The problem is when i have minified my code, i am getting following problem:

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

Please help me out any one who knows the solution. Thanks in advance.

r.js will detect deps to include from the array, but if the deps are dynamic like your case , it will not be detected

for dynamic deps, you may configure the build.js file to include this the dynamic deps you will require along with your module

assume below code

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 will not include mod1 and mod2 with main as they are not clear deps, so we have to instruct r.js that mod1 and mod2 are likely deps for main, we do this in 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"]
        }
    ]
})

by this setting, we instruct r.js to include mod1 and mod2 along with main.js

hope this was clear

The Problem

RequireJS' optimizer cannot perform dependency analysis on dependencies that are generated at run time. It would at least have the capability to execute your code in a way that would mirror what happens at run time, and there would still be cases that it would not be able to handle. So for RequireJS' dependency analysis to be successful, your dependencies must be literal arrays of strings. In any other situation, RequireJS will fail to perform the analysis, and it will fail silently.

In your case, this has two consequences:

  1. The optimizer does not actually give a name to your module. This explains the Mismatched anonymous define() module .

    One of the functions of the optimizer is to give modules their final names. So a module which you put in main.js , for instance, when it is not yet optimized would be transformed so that it is defined as define("main", ... . The optimizer adds the name to the start of the define call. (It does so only if the module has not yet been named.)

    How can you tell your module is not named by the optimizer? Besides the error message, which is a major clue, if you look at what r.js produces, you'll find your module defined as define(deps,function . Notice how the first argument of your module is not its name.

    You'll also see a stub following it. The stub looks like this define("main",function(){}) . This stub should only be present if the code of the module is not an actual AMD-style module. For instance, modules for which you must use a shim configuration would have these stubs. Your module, however, does not need this stub.

    At any rate, the optimizer is completely confused and does not name your module properly.

  2. The optimizer does not find the dependencies of your module.

Solution: Adapt the Build

mfarouk has already mentioned how to modify your build so that the second consequence above is taken care of. I'll just mention that the general rule is this: you must explicitly put in the include for your module the union of all modules that the optimizer misses. It would look like this:

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

where dependency1 , etc. are the dependencies in your deps array.

To take care of the first consequence, you need additional customization. I would suggest using the onBuildRead option of the optimizer:

onBuildRead: function (moduleName, path, contents) {
    if (moduleName !== "main")
        return contents;

    return contents.replace(/define\(deps/,
                            'define("' + moduleName + '",deps');
}

This function is invoked when the optimizer reads each module. When it reads main , the define call is modified to add the module name. The optimizer will then see that the module is already named, will leave the name alone, and won't generate a spurious stub.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM