2013-07-03 3 views
48

C'è un modo per definire un modulo che carica "dinamicamente" altri moduli in RequireJS? Se sì, come l'ottimizzatore (r.js) comprende come/quando un modulo deve essere incluso?Dynamic richiede in RequireJS, ottenendo l'errore "Il nome del modulo non è stato ancora caricato per il contesto"?

Ad esempio, supponiamo dynModules un modulo che definisce coppie nome/percorso:

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

altro modulo sta per caricare i moduli dinamicamente, basato sulla matrice. Questo non funziona:

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

    // ... 
}); 

... mi dà:

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

posso risolvere l'errore, ma non è "dinamico" più:

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

    // ... 
}); 

risposta

61

La limitazione si riferisce alla sintassi CommonJS semplificata rispetto alla normale sintassi di callback:

caricare un modulo è intrinsecamente un processo asincrono a causa della tempistica ignoto di scaricarlo. Tuttavia, RequireJS in emulazione delle specifiche CommonJS lato server tenta di darti una sintassi semplificata. Quando fai qualcosa di simile:

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

Quello che sta succedendo dietro le quinte è che RequireJS sta guardando il corpo del vostro codice di funzione e l'analisi che è necessario 'foo' e il caricamento prima della esecuzione della funzione. Tuttavia, quando una variabile o qualcosa di diverso da una semplice stringa, come il tuo esempio ...

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

... quindi richiede è in grado di analizzare questo fuori e convertire automaticamente. La soluzione è convertire la sintassi di callback;

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

luce di quanto sopra, ecco una possibile riscrittura del tuo secondo esempio per utilizzare la sintassi 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: Dal vostro risposta, vedo che si sta utilizzando sottolineare/lodash, pertanto l'utilizzo di _.values e _.object può semplificare il ciclo attraverso la matrice di argomenti come sopra.

+2

Grazie per il vostro tempo, ho trovato una soluzione dopo la ricerca sul sito RequireJS. Vedi la mia risposta. – gremo

+0

L'unica domanda che ho è: usare 'require (_. Values ​​(Config), ...)' è un codice asincrono, giusto? Ciò significa che ho bisogno di usare lo stile di callback quando termina 'require', giusto? – gremo

+0

Sì, e si sta utilizzando la sintassi di richiamata nella risposta. 'require (_. values ​​(Config), function() {' è approssimativamente equivalente a 'require (dynModules, function() {' nella mia. Entrambi usano una serie di stringhe come primo parametro e forniscono una funzione per la callback come 2 ° parametro – explunit

5

Rispondere a me stesso. Dal sito RequireJS:

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

Questo non riesce a causa requirejs ha bisogno di essere sicuri di caricare ed eseguire tutte le dipendenze prima di chiamare la funzione di fabbrica di cui sopra. [...] Quindi, non passare nell'array delle dipendenze, o se si utilizza l'array di dipendenze, elencare tutte le dipendenze in esso.

La mia soluzione:

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

Il caricatore:

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

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

     // Use deps... 
    }); 
}); 
+0

Nope, 'modules 'si suppone che sia definito in un altro modulo, ad esempio un file di configurazione.Per mezzo va bene – gremo

+0

@explunit vedere la mia risposta aggiornata – gremo

+0

sembra che la chiave sia ancora la conversione dalla sintassi sincrona CommonJS alla sintassi callback RequireJS. – explunit

Problemi correlati