web-dev-qa-db-fra.com

Requiert dynamique dans RequireJS, obtenant l'erreur "Le nom du module n'a pas encore été chargé pour le contexte"?

Existe-t-il un moyen de définir un module qui charge "dynamiquement" d'autres modules dans RequireJS? Si oui, comment l'optimiseur (r.js) comprend-t-il comment/quand un module doit être inclus?

Par exemple, prenons dynModules un module qui définit les paires nom/chemin:

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

Un autre module va charger des modules dynamiquement, en fonction du tableau. Cela ne fonctionnera pas :

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

    // ...
});

... Donne moi:

Erreur non capturée: le nom du module "moduleA" n'a pas encore été chargé pour le contexte: _. Utilisez require ([]) http://requirejs.org/docs/errors.html#notloaded

Je peux résoudre l'erreur , mais ce n'est plus "dynamique":

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

    // ...
});
56
gremo

La limitation concerne la syntaxe simplifiée CommonJS par rapport à la syntaxe de rappel normale:

Le chargement d'un module est intrinsèquement un processus asynchrone en raison du moment inconnu de son téléchargement. Cependant, RequireJS dans l'émulation de la spécification CommonJS côté serveur essaie de vous fournir une syntaxe simplifiée. Quand vous faites quelque chose comme ça:

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

En coulisse, RequireJS examine le corps de votre code de fonction et analyse le fait que vous avez besoin de "foo", puis le charge avant l'exécution de votre fonction. Cependant, lorsqu'une variable ou autre chose qu'une simple chaîne, telle que votre exemple ...

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

... alors Require est incapable d'analyser cela et de le convertir automatiquement. La solution consiste à convertir à la syntaxe de rappel;

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

Compte tenu de ce qui précède, voici une possibilité de réécriture de votre deuxième exemple pour utiliser la syntaxe standard:

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: D'après votre propre réponse, je vois que vous utilisez un trait de soulignement/lodash, donc vous utilisez _.values et _.object peut simplifier la lecture en boucle des arguments comme ci-dessus.

68
explunit

Répondre à moi-même. Sur le site Web RequireJS:

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

Cela échoue parce que requirejs doit s'assurer de charger et d'exécuter toutes les dépendances avant d'appeler la fonction fabrique ci-dessus. [...] Donc, ne passez pas dans le tableau de dépendances ou, si vous utilisez le tableau de dépendances, répertoriez toutes les dépendances qu'il contient.

Ma solution:

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

Le chargeur:

define(['jade', 'lodash', 'config'], function (Jade, _, Config) {
    var deps;

    // Dynamic require
    require(_.values(Config), function () {
        deps = _.object(_.keys(Config), arguments);

        // Use deps...
    });
});
7
gremo