2015-09-09 18 views
14

Na mojej stronie internetowej ładuję większość skryptów asynchronicznie za pomocą RequireJs. Proszę zobaczyć następujące mojej konfiguracji RequireJs:Wystąpił problem podczas ładowania wielu wersji jQuery

require.config({ 
    paths: { 
     'jquery': '//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery' 
    }, 
    shim: { 
     'jquery.accordion': { 
      deps: ['jquery'] 
     } 
    } 
}); 

że mam następujący kod zdefiniowany w organizmie, aby załadować plik asynchronicznie:

require(['DisplayAccordion']); 

Gdzie DisplayAccordion.js zawiera następujące elementy:

define(['jquery', 'jquery.accordion'], function($) { 
    $(function() { 
     $('.xyz').accordion(); 
    }); 
}); 

Uwaga: jquery.accordion to po prostu wtyczka jQuery, która nie obsługuje AMD i wymaga zdefiniowania globalnej zmiennej jQuery.

To działa dobrze, ale teraz mówię, że umieszczam odnośnik do skryptu na mojej stronie w bibliotece innej firmy. Na przykład:

<script src="//example.com/ThirdParty.js"></script> 

Tam, gdzie biblioteka stron trzecich ładuje swoją własną wersję jQuery. Teraz otrzymuję błąd:

Object doesn't support property or method 'accordion'.

Po wstępnej poprzez kod znalazłem, że wykonuje się w następującej kolejności:

  1. ThirdParty.js
  2. jquery.min.js - wersja strony trzeciej
  3. jquery.min.js - moja wersja
  4. jquery.accordion.js - gdzie $ punkty odniesienia do mojej wersji jQuery
  5. Displ ayAccordion.js (funkcja zwrotna) - gdzie $ wskazuje na trzecią wersję jQuery

Teraz widzę, dlaczego dostaję błąd, ponieważ wtyczka jest dołączona do innego obiektu. Jednak nie jestem pewien, dlaczego to zrobiłoby.

Poniższe informacje wyjaśniają, dlaczego użycie $ .noConflict (true) nie zadziała.

Po przeprowadzeniu badań w tej sprawie. I zmodyfikowane mój config:

require.config({ 
    paths: { 
     'jquery': '//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery' 
    }, 
    map: { 
     '*': { 'jquery': 'jquery-private' }, 
     'jquery-private': { 'jquery': 'jquery' } 
    }, 
    shim: { 
     'jquery.accordion': { 
      deps: ['jquery'] 
     } 
    } 
}); 

Gdzie jQuery private.js jest zdefiniowany jako:

define(['jquery'], function($) { 
    return $.noConflict(true); 
}); 

Należy pamiętać, że ta została podjęta z http://www.requirejs.org/docs/jquery.html#noconflictmap

Teraz wykonuje się w następującej kolejności:

  1. ThirdParty.js
  2. jquery.min.js - wersja osoba trzecia
  3. jQuery private.js (funkcja zwrotna)
  4. jquery.min.js - moja wersja
  5. jquery.accordion.js - gdzie $ jest niezdefiniowana
  6. DisplayAccordion .js (funkcja callback) - gdzie $ punkty do trzeciej wersji partyjnej jQuery

Jak można sobie wyobrazić, to nie będzie działać albo od $ jest zdefiniowana w pliku jquery.accordion.js.

Po abit dalszego debugowania odkryłem biblioteki strona trzecia wzywa również:

$.noConflict(true); 

Chyba rozumiem, co się tu dzieje. Kiedy wywołuje $ .noConflict (true) w bibliotece trzeciej strony, próbuje ustawić globalne zmienne $ i jQuery do poprzedniej wersji. Ponieważ jednak nie załadowano poprzedniej wersji, jest ona ustawiona na undefined.

Teraz, gdy wywołuje jquery-private.js i zwraca $ .noConflict (true), zwróci globalną zmienną jQuery, która została ustawiona na undefined. Jednak teraz ustawi globalną zmienną jQuery na trzecią wersję biblioteki.

Tak więc po załadowaniu pliku jquery.accordion $ jest niezdefiniowany. Ale kiedy następnie wywołuje DisplayAccordion.js, odwołuje się teraz do trzeciej wersji biblioteki jQuery.

Byłbym wdzięczny, gdyby ktoś mógł zaproponować poprawkę. Dzięki

Odpowiedz

1

ja proponuję zrobić własną wersję jquery.accordion.js - co czyni go do modułu RequireJS (owinąć go w define(["jquery-private"], function($){ ... }); etc)

Wszystko inne musi poprosić o jquery-private zamiast jquery - więc jedyną wzmianką o jquery w wywołaniu require()/define() będzie w samym .

Chociaż oznaczałoby to, że nie można go załadować z automatycznie aktualizowanej sieci CDN firmy zewnętrznej, pozwoliłoby to uruchomić ją w "poprawnej" wersji jQuery.

W międzyczasie (jeśli wiesz, który to jest - GitHub wymienia kilka projektów o tej nazwie) możesz również przesłać zgłoszenie błędu/żądanie ściągnięcia do GitHub, aby umożliwić obsługę RequireJS - a następnie zmienić ścieżkę po jej aktualizacji :-)

+0

To nie rozwiąże problemu. Zauważ, jak w ostatnim kroku próby OP (obu prób) moduł 'DisplayAccordion', który * robi * ładuje' jquery' jako moduł, pobiera trzecią wersję jQuery zamiast wersji, którą chce OP. To, co sugerujesz, zrobi to samo: 'jquery.accordion' otrzyma wersję jQuery innej firmy niż wersję OP. Jeśli wyjaśnię to w mojej odpowiedzi, dlaczego tak się dzieje. – Louis

+0

Doh - widzę - główny problem z twoją odpowiedzią polega po prostu na tym, że ignoruje fakt, że OP nie ma kontroli nad kolejnością ładowania (dlatego nie pomaga w żaden inny sposób niż informacyjny). Jak o użyciu modułu 'jquery-private' zamiast' jquery' - nadal będzie wymagać zapakowania akordeonu, ale powinno pozwolić na użycie poprawnej wersji ... – Rycochet

+0

Użycie 'jquery-private' nie rozwiąże problemu . Tak postąpił PO podczas drugiej próby. Jak wskazałem w moim poprzednim komentarzu, w * obu * próbach 'DisplayAccordion' pojawia się niewłaściwa wersja. Co do wartości mojej odpowiedzi, tak, przeczytałem komentarz PO i zdałem sobie sprawę, że nie zadziała, jeśli nie można ograniczyć kolejności ładunków kodu OP względem "ThirdParty.js". Dla przypomnienia, OP dodał * zasadnicze * zastrzeżenie, że nie ma kontroli nad kolejnością ładowania * po * wysłałem odpowiedź. W każdym razie dla mnie oznacza to, że kolejność powinna być ograniczona. – Louis

1

Jedynym sposobem, w jaki mogę zobaczyć zachowanie, które się początkowo dzieje, jest załadowanie ThirdParty.jspo RequireJS zostało załadowane. Oto, co się stanie:

  1. RequireJS jest załadowany.

  2. ThirdParty.js ładuje.

  3. jquery.min.js ładuje wersja trzeciej strony. Sprawdza, czy istnieje define.amd. Czyni to, dlatego nazywa się define('jquery', ... i rejestruje się jako moduł AMD.

  4. jquery.min.js Twoja wersja ładuje się. Być może zastanawiasz się, dlaczego RequireJS zawracałoby sobie głowę ładowaniem tego, gdyby już zdefiniowano jquery. Być może mamy tu do czynienia z kondycją wyścigową. Jeśli jest coś, co wyzwoliło ładowanie jquery przed krokiem 3, oczekiwałbym, że RequireJS zaplanuje niepotrzebne obciążenie twojej wersji jQuery. define('jquery', ... zostanie ponownie wywołany, ale nic nie zrobi z powodu pierwszego połączenia wcześniej.

  5. jquery.accordion.js wykonuje, gdzie $ wskazuje na twoją wersję jQuery. Tak, ponieważ w kroku 4 globalna $ została ustawiona na twoją wersję.

  6. DisplayAccordion.js wykonuje, gdzie $ wskazuje na trzecią wersję jQuery. Tak, ponieważ w kroku 3 jest to trzecia wersja, która została zarejestrowana jako moduł.

Aby rozwiązać ten problem, chciałbym się upewnić, że ThirdParty.js i jego wersji jQuery obciążenia przed RequireJS. Sposób osiągnięcia tego zależy od tego, w jaki sposób ładuje się jQuery. Od ThirdParty.js dzwoni $.noConflict, powinieneś być w porządku po tym z ładowaniem własnego kodu i nie otrzymywania zakłóceń.

+1

Dzięki zapomniałem, że jQuery miał ten mały bit definiujący na dole. Niestety Twoja sugerowana poprawka nie jest możliwa, ponieważ ten kod jest częścią systemu zarządzania treścią, a mój klient może usunąć skrypty stron trzecich w dowolnym miejscu w treści strony. – nfplee

Powiązane problemy