Niedopasowany moduł anonimowy define ()

129

Dostaję ten błąd, gdy mogę przeglądać mój webapp po raz pierwszy (zwykle w przeglądarce z niepełnosprawnej cache).

Błąd: niezgodny anonimowy moduł define (): funkcja (wymóg) {

HTML :

<html>
   .
   .
   .
   <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
   <script> var require = { urlArgs: "v=0.4.1.32" }; </script>
   <script data-main="assets/js/main" src="assets/js/libs/require.js"></script>
   <script src="assets/js/ace/ace.js?v=0.4.1.32"></script>
   </body>
</html>

JS :

$(function () {
    define(function (require) {
        // do something
    });
});

Czy ktoś dokładnie wie, co oznacza ten błąd i dlaczego się dzieje?

plik źródłowy , krótka dyskusja na ten temat na stronie problemów github

Adonis K. Kakoulidis
źródło

Odpowiedzi:

142

Jak powiedział AlienWebguy, zgodnie z dokumentacją, require.js może wybuchnąć, jeśli

  • Masz anonimową definicję („ moduły, które wywołują define () bez identyfikatora ciągu ”) we własnym tagu skryptu (zakładam, że w rzeczywistości oznaczają one w dowolnym miejscu w zasięgu globalnym)
  • Masz moduły, które mają sprzeczne nazwy
  • Używasz wtyczek modułu ładującego lub anonimowych modułów, ale nie korzystasz z optymalizatora require.js do łączenia ich w pakiety

Miałem ten problem podczas dołączania pakietów zbudowanych za pomocą browserify wraz z modułami require.js. Rozwiązaniem było:

A. załaduj samodzielne pakunki non-require.js w znacznikach script przed załadowaniem require.js lub

B. załaduj je za pomocą require.js (zamiast tagu script)

BT
źródło
2
sprzeczne nazwy są powszechne
Julio Marins
1
Innym możliwym rozwiązaniem, w niektórych specjalnych przypadkach z anonimowymi modułami, jest nadpisanie funkcji requirejs.onError w celu uniknięcia domyślnego wyjątku błędu generowanego przez requirejs, który zatrzymuje kolejne moduły lub kod do wykonania.
xtrm
1
Właśnie dodałem żądanie ściągnięcia ( github.com/requirejs/requirejs/pull/1763 ), aby złagodzić ten konkretny przypadek. Myślę, że to bardzo powszechny problem w dzisiejszych czasach.
Bob S,
1
Dziękuję, że kazałeś mi je wcześniej załadować! Nie wiem, dlaczego ta wskazówka nie znajduje się w dokumentacji requirejs ... Tutaj przydaje się stos
Tobias Feil
14

Wystąpił ten błąd, ponieważ dołączyłem plik requirejs wraz z innymi bibliotekami zawartymi bezpośrednio w tagu skryptu. Te librairies (jak lodash) używały funkcji define, która była sprzeczna z definicją require. Plik requirejs ładował się asynchronicznie, więc podejrzewam, że definicja wymagania została zdefiniowana po zdefiniowaniu przez inne biblioteki, stąd konflikt.

Aby pozbyć się tego błędu, dołącz wszystkie inne pliki js, używając requirejs.

eloone
źródło
Okazało się, że wiele bibliotek to robi, a przynajmniej używa / eksportuje taką funkcję. Radzę wszystkim - jeśli używają wymagają - zaimportuj wszystko z require :)
Andrey Popov
12

Rozpoczynając pracę z actjs, natknąłem się na problem i jako początkujący z docs równie dobrze może być napisany w języku greckim.

Problem, na który natknąłem się, polegał na tym, że większość początkujących przykładów używa „anonimowych definicji”, kiedy powinieneś używać „identyfikatora ciągu”.

anonimowe definiuje

define(function() {
        return { helloWorld: function() { console.log('hello world!') } };
 })


define(function() {
        return { helloWorld2: function() { console.log('hello world again!') } };
 })

zdefiniuj z identyfikatorem ciągu

define('moduleOne',function() {
    return { helloWorld: function() { console.log('hello world!') } };
})

 define('moduleTwo', function() {
      return { helloWorld2: function() { console.log('hello world again!') } };
})

Używając define z identyfikatorem ciągu , unikniesz tego błędu, gdy będziesz próbował użyć modułów w następujący sposób:

require([ "moduleOne", "moduleTwo" ], function(moduleOne, moduleTwo) {
    moduleOne.helloWorld();
    moduleTwo.helloWorld2();
});
P. Brian Mackey
źródło
(Tylko uwaga dla potomnych) Tam pewne wady tego podejścia opisane w docs : „define () wywołuje, które zawierają nazwę modułu ... są zwykle generowane przez narzędzie do optymalizacji ... Nam [ing] Moduły sobie ... sprawia, że moduły mniej przenośne… Zazwyczaj najlepiej jest unikać kodowania w nazwie modułu i po prostu pozwolić narzędziu optymalizującemu wypalić nazwy modułów. ” … Jak również w tym wątku GitHub . Wydaje się, że jest to powód, dla którego wymienienie nazwy jest wykluczone w przykładach dla początkujących.
Mark G.
10

Zgodnie z dokumentacją :

Ten błąd może wystąpić, jeśli ręcznie zakodujesz znacznik skryptu w języku HTML, aby załadować skrypt z anonimowym wywołaniem define ().

Widoczne również, jeśli ręcznie zakodujesz tag skryptu w HTML, aby załadować skrypt, który ma kilka nazwanych modułów, ale następnie spróbujesz załadować anonimowy moduł, który w końcu będzie miał taką samą nazwę jak jeden z nazwanych modułów w skrypcie załadowanym ręcznie kodowany tag skryptu.

Wreszcie, jeśli używasz wtyczek modułu ładującego lub anonimowych modułów (modułów, które wywołują funkcję define () bez identyfikatora ciągu), ale nie używasz optymalizatora RequireJS do łączenia plików, może wystąpić ten błąd. Optymalizator wie, jak poprawnie nazywać anonimowe moduły, aby można je było łączyć z innymi modułami w zoptymalizowanym pliku.

Aby uniknąć błędu:

  • Pamiętaj, aby załadować wszystkie skrypty, które wywołują define () za pośrednictwem interfejsu API RequireJS. Nie należy ręcznie kodować znaczników skryptów w języku HTML w celu ładowania skryptów, które zawierają wywołania define ().

  • Jeśli ręcznie kodujesz znacznik skryptu HTML, upewnij się, że zawiera on tylko nazwane moduły, a moduł anonimowy, który będzie miał taką samą nazwę jak jeden z modułów w tym pliku, nie zostanie załadowany.

  • Jeśli problemem jest użycie wtyczek modułu ładującego lub anonimowych modułów, ale optymalizator RequireJS nie jest używany do tworzenia pakietów plików, użyj optymalizatora RequireJS.

AlienWebguy
źródło
3
Czy jest to moduł zdefiniowany anonimowo? github.com/requirejs/example-multipage/blob/master/www/js/app/...
streetlight
5

Należy pamiętać, że niektóre rozszerzenia przeglądarki mogą dodawać kod do stron. W moim przypadku miałem wtyczkę „Emmet we wszystkich obszarach tekstowych”, która zepsuła moje wymagania. Upewnij się, że żaden dodatkowy kod nie został dodany do twojego dokumentu, sprawdzając go w przeglądarce.

Wektor
źródło
5

Istniejące odpowiedzi dobrze wyjaśniają problem, ale jeśli dołączenie plików skryptów przy użyciu lub wcześniej niż requireJS nie jest łatwą opcją ze względu na starszy kod, nieco hackerskim obejściem jest usunięcie wymagania z zakresu okna przed tagiem skryptu, a następnie przywrócenie go po słowach. W naszym projekcie jest to opakowane za wywołaniem funkcji po stronie serwera, ale w rzeczywistości przeglądarka widzi:

    <script>
        window.__define = window.define;
        window.__require = window.require;
        window.define = undefined;
        window.require = undefined;
    </script>
    <script src="your-script-file.js"></script>        
    <script>
        window.define = window.__define;
        window.require = window.__require;
        window.__define = undefined;
        window.__require = undefined;
    </script>

Nie jest to najładniejsze, ale wydaje się działać i zaoszczędziło wiele refraktorów.

jcbdrn
źródło
5
Właściwie nigdy tego nie rób. Nie działa poprawnie w IE.
jcbdrn
2
Sporadycznie w IE skrypty zawarte w requireJS musiałyby zdefiniować brakujące w zakresie ich okna, nawet jeśli polecenie require przyszło po przywróceniu tych zmiennych. Nigdy nie udało nam się dowiedzieć, dlaczego tak się stało, więc porzuciliśmy to hackerskie rozwiązanie.
jcbdrn
2
@jcbdrn Nie tylko w IE. Widziałem to na innej platformie. Powodem jest to, że specyfikacja HTML zapewnia gwarancje dotyczące kolejności wykonywania skryptów synchronicznych, ale tylko w odniesieniu do innych skryptów synchronicznych . Nie gwarantuje wykonywania skryptów asynchronicznych względem skryptu synchronicznego (lub odwrotnie). Tak więc w kodzie przedstawionym w odpowiedzi tutaj możliwe jest wykonanie asynchronicznego skryptu między dowolnymi dwoma scriptelementami.
Louis
Jeśli masz możliwość edycji pakietu js, który importujesz, możesz po prostu opakować całość w ten sposób:(function(){ var define = undefined; // the UMD registration code won't find the global 'define' anymore! // generated content goes here })()
Pete Thorne
2

Lub możesz skorzystać z tego podejścia.

  • Dodaj require.js w swojej bazie kodu
  • następnie załaduj swój skrypt za pomocą tego kodu

<script data-main="js/app.js" src="js/require.js"></script>

To, co zrobi, spowoduje załadowanie skryptu po załadowaniu require.js .

Umar Asghar
źródło