W tym tygodniu zajmiemy się loaderem zależności RequireJS (ładowanie dynamiczne plików które są w danej chwili potrzebne a nie wszystkich bo tak) zgodnym ze specyfikacją AMD (Asynchronous Module Definition), która jest modyfikacją formatu transportu z CommonJS, której jedna z wersji jest zaimplementowana w Node.

Różnica pomiędzy RequireJS i CommonJS jest taka, że jedno implementuje specyfikację AMD i jest skierowane do przeglądarek, zaś drugie implementuje wzorzec definiowana modułów poprzez globalną zmienną exports i ładowania poprzez require i jest bardziej skierowane na stronę serwerową.

Ogólnie RequireJS sprowadza się (w prostej formie) do definicji modułu i jego wykorzystania. Podobnie jak w CommonJS, ale w inny sposób (choć dla jaj RequireJS posiada wrapper na CommonJS… jakie to wszystko jest pokręcone). Jeżeli moduł/plik nie zostało jeszcze załadowany, to zostanie on dynamicznie wczytany zanim zostanie wykonana pierwsza linijka moduły/pliku wykorzystującego dany moduł/plik.

RequireJS

W najprostszej postaci nasza aplikacja, wykorzystująca RequireJS będzie wyglądało tak:

// index.html
<script scr="js/lib/require.js" data-main="js/main"></script>

// main.js
requirejs(['app']);

// app.js
define(function () {
    console.log('loaded!');
});

Gdzie, nasz skrypt robi referencje do RequireJS, które po załadowaniu sprawdza data-main atrybut i ładuje zależność tam zdefiniowaną. Następnie w tej zależności bootstrapujemy naszą aplikację poprzez jej “wymaganie” do załadowania w requirejs. Dzięki czemu app.js zostanie odpalony.

Tutaj warto zaznaczyć, że domyślnie RequireJS nazywa nasze moduły w postaci NAZWA_PLIKU z pominięciem jego rozszerzenia. Więc app.js to app. Oczywiście możemy dodawać rozszerzenia, ale wtedy RequireJS traktuje naszą referencję relatywną ścieżkę od adresu pod którym nasz dokument został załadowany – czyli pomija opcję konfiguracyjną baseUrl.

Prosto? Prosto, fajne? Fajnie. Jakby tak wszystkie projekty były proste i piękne to życie usłane było by różami. Niestety, nie wszystko tak ładnie wygląda z RequireJS jak powyższy przykład. Dlatego też możemy tworzyć konfigurację, która nie tylko umożliwi nam zdefiniowanie bibliotek zewnętrznych ale także, zdefiniuje folder bazowy dla naszej aplikacji jak i shimy na biblioteki nie wspierające RequireJS. Opcji jest sporo i warto zapoznać się z dokumentacją, w najprostszej postaci jednak plik konfiguracyjny wygląda tak:

require.config({
    baseUrl: '/my/app/path'
});

Ale znów, życie nie jest takie proste i nasz plik konfiguracyjny potrafi się bardzo szybko rozrosnąć (wszystkie opcje w jednym pliku) w szczególności kiedy korzystamy z bower – wtedy każdy pojedynczy komponent trzeba będzie wypisać w pliku konfiguracyjnym. Przydaje się tutaj wykorzystać plugin bower-requirejs, który tą mozolną pracę trochę ułatwi.

Oczywiście jak wchodzi nam konfiugracja to pojawia się problem, co jest pierwsze, jajko czy kura. Jeżeli już takie pytania się pojawiają to także pojawia się lista możliwych rozwiązań – ja osobiście korzystam z opcji 4, to znaczy, że zamiast ładować main.js, ładuje config.js, który ma zdefiniowane zależności za pomocą własności deps. Wtedy te zależności muszą zostać załadowane :) proste, ale i tak..dziwne.

require.config({
    deps: ["app"]
});

Kolejną rzeczą o której warto wspomnieć, to możliwość ładowania plików min – w końcu po co na live wersja nie zminifikowana? Ogólnie, wbudowanej opcji nie ma. Istnieje zaś narzędzie RequireJS optimizer które odpowiedzialne jest za grupowanie współzależnych plików w jeden. To znaczy, jeżeli strona A wymaga  X i Y, to te dwa zostaną połączone w jeden plik, zaś moduł Z zostanie pominięty – gdyż nie był wymagany. Na stronie B zaś zostaną jedynie załączone moduły X i Z gdyż tylko takie są wymagane. Najgorsze w tym jest to, że mimo iż przeczytałem dokumentację do optymalizacji to dalej mam z tym kłopot. Może chłopaki jednak mogli by nad docsami popracować :)

Podsumowanie

RequireJS nie jest jedynym narzędziem które spełnia specyfikację AMD, ale chyba jednym z najbardziej popularnych. Dlatego warto wiedzieć do czego służy i z czym się go je.

Nie zmienia to jednak faktu, że RequireJs nie przypadł mi do gusty i jakbym mógł to bym z niego nie korzystał. Z drugiej strony, jest on jakimś wyjściem/rozwiązaniem dynamicznego ładowania zależności wtedy kiedy są nam one potrzebne, a nie wtedy kiedy na wszelki wypadek je dodajemy do strony.

Nie wchodziłem także tutaj w szczegóły, IMO wszystko co najważniejsze zostało zawarte, to czego nie pokazałem to jak stworzyć  aplikację z wykorzystaniem RequireJS, ale tutaj przychodzą nam na ratunek 3 przykłady z dokumentacji:

To są proste przykłady, które szybko umożliwiają nam wystartowanie. Jeżeli chcemy bardziej złożone, real-life to już pan google wam pomoże. Tego jest masa, bo też ciężko o alternatywę… ale o tym za tydzień :)

2 KOMENTARZE

Comments are closed.