Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
229 views
in Technique[技术] by (71.8m points)

javascript - Loading requirejs modules Dynamically with sugar syntax

Hi i am trying to load some requireJs modules in a dynamic way by getting a list of filters and the iterate over the array to load this modules like this

define(function(require){
var runFilters = function(filters){
    var _ = require('underscore');
    var computedFilters  = getFilters(filters);
    var result = _.every(computedFilters,function(filter){
        return filter();
    });
    return result;
};

var getFilters = function(filters){
    var _ = require('underscore');
    return _.map(filters,function(filter){
        return require('filters/' + filter);
    },this);
}


var register = function(filters,fn){
    return function(){
        var args = Array.prototype.slice.apply(arguments);
        if(runFilters(filters))
            fn.apply(this,args);
    }
}
return{
    register: register
}
});

This give me error: Uncaught Error: Module name "filters/isAuth" has not been loaded yet for context: _

but when replacing this to a static way (just to test) it loads perfectly

define(function(require){
    var runFilters = function(computedFilters){
        var result = _.every(computedFilters,function(filter){
            return filter();
        });
        return result;
    };

    var getFilters = function(filters){
        var _ = require('underscore');
        return _.map(filters,function(filter){
            console.log(filter);
            return require('filters/' + filter);
        },this);
    }


    var register = function(filters,fn){
        var cachedFilters = [];
        cachedFilters.push(require('filters/isAuth'));
        return function(){
            var args = Array.prototype.slice.apply(arguments);
            if(runFilters(cachedFilters))
                fn.apply(this,args);
        }
    }
    return{
        register: register
    }
});

this give me the error too

cachedFilters.push(require('filters'+'/isAdmin'));
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You've run into a limitation of RequireJS's support for the CommonJS syntax. Here's the deal. When RequireJS defines a module, it looks at the factory function (the callback) you gave to define. It looks for this pattern:

/[^.]s*requires*(s*["']([^'"s]+)["']s*)/g

This matches require calls like var foo = require('foo'); For each such call, it adds the required module to the list of dependencies of your module. So, for instance, something like:

// The `require` parameter must be present and is filled with something useful
// by RequireJS.
define(function (require) {
    var foo = require('foo');
    var bar = require('bar');
    ...
});

Is treated like this:

define(['require', 'foo', 'bar'], function (require) {
    var foo = require('foo');
    var bar = require('bar');
    ...
});

If you look carefully at the regular expression above, you'll see it will match only require calls that have a single parameter which is a literal string. So things like require("something" + somevar) won't work. RequireJS completely ignores them when doing this transformation.

The issue would not be fixable by changing the regular expression. RequireJS is at its heart a system for loading modules asynchronously. The form of the require call with a single string literal is sugar to allow porting more easily modules designed according to the CommonJS pattern, and for those who prefer this style (even if they are not porting anything). This type of call looks synchronous without actually being synchronous. To support cases where the name passed to it is computed, RequireJS would have to predict what the value would be.

If you want to have complete freedom to load whatever module you want in your code without knowing ahead of time what the name may be, then you have to use an asynchronous require call (require([computed_value], function(mod) {...})) which means your code must be asynchronous. If you have a limited set of modules you want to load and it is acceptable to always load them all, then you could require them all with literal strings:

define(function (require) {
    require("filters/isAdmin");
    require("filters/b");
    require("filters/c");
    require("filters/d");
    ...
});

RequireJS would do the transformation above and further require calls using computed values that resolve to one of the names you required early in your module would not fail.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...