Dynamic requirement in RequireJS, because the error "Module name error has not yet been loaded for context"?

Is there a way to define a module that dynamically loads other modules in RequireJS? If so, how does the optimizer (r.js) understand how / when the module should be included?

For example, let the dynModules module that defines name / path pairs:

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

Another module will load the modules dynamically based on the array. This will not work :

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

... gives me:

Unsuccessful error: module name "moduleA" has not yet been loaded for context: _. Use require ([]) http://requirejs.org/docs/errors.html#notloaded

I can solve the error , but it is no longer "dynamic":

 define(['dyn_modules', 'moduleA', 'moduleB'], function (dynModules) { for(name in dynModules) { var module = require(path); // Call RequireJS require } // ... }); 
+48
javascript browser module requirejs
Jul 03 '13 at 11:33
source share
2 answers

The limitation relates to the simplified CommonJS syntax versus the standard callback syntax:

Loading a module is essentially an asynchronous process due to an unknown loading time. However, RequireJS in emulating the server specification of CommonJS is trying to give you a simplified syntax. When you do something like this:

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

What happens behind the scenes is that RequireJS looks at the body of your functional code and analyzes what you need to "foo" and load it before your function executes. However, when a variable or nothing but a simple string, for example, your example ...

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

... then Require cannot parse this and automatically convert it. The solution is to convert to callback syntax;

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

Given the above, here is one possible way to repeat your second example using the standard syntax:

 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... } }); }); 

EDIT: from your own answer, I can see that you are using underscore / lodash, so using _.values and _.object can simplify the loop using an array of arguments as above.

+60
Jul 03 '13 at 13:05
source share

Answering the question. From the RequireJS website:

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

This fails because requirejs must download and execute all the dependencies before calling the factory function above. [...] So, either do not go into the array of dependencies, or if you are using an array of dependencies, list all the dependencies in it.

My decision:

 // 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' }; }); 

Loader:

 define(['jade', 'lodash', 'config'], function (Jade, _, Config) { var deps; // Dynamic require require(_.values(Config), function () { deps = _.object(_.keys(Config), arguments); // Use deps... }); }); 
+5
Jul 03 '13 at 13:06 on
source share



All Articles