2013-07-03 25 views
48

Czy istnieje sposób zdefiniowania modułu, który "dynamicznie" ładuje inne moduły w RequireJS? Jeśli tak, to w jaki sposób optymalizator (r.js) rozumie, w jaki sposób/kiedy moduł musi zostać uwzględniony?Dynamiczne wymagają w RequireJS, otrzymując komunikat "Błąd nazwy modułu nie został jeszcze załadowany dla kontekstu"?

Na przykład, niech dynModules moduł, który określa par nazwa/ścieżka:

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

Innym moduł ma ładowania modułów dynamicznie na podstawie tablicy. To będzie nie działać:

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

    // ... 
}); 

... daje mi:

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

mogę rozwiązać błąd, ale to nie jest "dynamiczny" już:

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

    // ... 
}); 

Odpowiedz

61

Ograniczenie dotyczy uproszczonej składni CommonJS w porównaniu do zwykłej składni wywołania zwrotnego:

Ładowanie moduł jest z natury procesem asynchronicznym z powodu nieznanego terminu pobierania. Jednak RequireJS w emulacji specyfikacji CommonJS po stronie serwera próbuje podać uproszczoną składnię. Kiedy robisz coś takiego:

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

Co się dzieje za kulisami jest to, że RequireJS patrzy na ciało swojego kodu funkcji i analizowania, że ​​trzeba „foo” i ładuje go przed wywołaniem funkcji. Jednak, gdy zmienna lub czymkolwiek innym niż prosty ciąg znaków, takich jak np ...

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

... potem Wymagaj nie jest w stanie przetworzyć na to uwagę i automatycznie konwertować je. Rozwiązaniem jest konwersja do składni wywołania zwrotnego;

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

Biorąc powyższe pod uwagę, jest tu jeden z możliwych przepisać Twojego 2nd przykład wykorzystania standardowej składni:

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: Od swoją odpowiedź, widzę, że używasz podkreślenia/lodash, więc używanie _.values i _.object może uprościć przechodzenie przez tablicę argumentów jak wyżej.

+2

Dzięki za poświęcony czas, znalazłem rozwiązanie Po poszukiwaniach na stronie RequireJS. Zobacz moją odpowiedź. – gremo

+0

Jedynym Mam pytanie jest: używanie 'wymagają (_ wartości (config), ....)' Jest kod asynchroniczny, prawda? Oznacza to, że muszę używać stylu wywołania zwrotnego, gdy kończy się 'require', prawda? – gremo

+0

Tak, i używasz składni wywołania zwrotnego w swojej odpowiedzi. 'Wymagające (_. Wartości (config), funkcja() {' jest w przybliżeniu równa 'wymagają (dynModules funkcja() {' w kopalni. Zarówno użyć zestawu napisów jako pierwszy parametr i dostarczyć funkcję wywołania zwrotnego Jako 2. parametr – explunit

5

Odpowiadanie na siebie. Od strony RequireJS:

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

To nie działa, ponieważ requirejs musi mieć pewność, aby załadować i wykonać wszystkie zależności przed wywołaniem powyżej funkcji fabrycznego. [...] Tak więc albo nie przechodź w tablicy zależności, albo jeśli korzystasz z tablicy zależności, wypisz wszystkie zależności w niej.

Moje rozwiązanie:

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

Ładowarka:

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

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

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

Nie, 'moduły 'ma być zdefiniowana w innym module, czyli pliku konfiguracyjnym. współpracuje btw. – gremo

+0

@explunit zobaczyć moją zaktualizowaną odpowiedź. – gremo

+0

wygląda klucz jest nadal konwersja z CommonJS synchronicznego składni składni wywołania zwrotnego RequireJS. – explunit