SPA 3. časť: Pekelné závislosti 2

130

Vyvíjať veľkúreload javascriptovú aplikáciu (napr. SPA) a udržať v nej poriadok, si vyžaduje písať modulárny kód a rozdeliť aplikáciu do viacerých súborov v prehľadnej adresárovej štruktúre.

Ak má aplikácia fungovať, treba súbory v správny čas načítať na stránke a treba to spraviť v správnom poradí – jednotlivé moduly na sebe môžu závisieť. Robiť takýto dependency loading ručne je na zbláznenie, preto má väčšina jazykov nejakú formu príkazov includerequire, či import. Žiaľ, Javascript túto fičúriu do vienka nedostal.

RequireJS

Našťastie sa na scéne zjavil záchranca, ktorý naše problémy vyrieši. Táto šikovná knižnica pomáha vytvárať moduly, popísať ich závislosti a nezaprasiť si globálny namespace. To všetko v súlade s AMD štandardom. Stačí nainštalovať pomocou bower install requirejs.

Takto vyzerá AMD zápis modulu bez závislostí v RequireJS.

//js/app/myfirstmodule.js
define(function() {
    //Do setup work here.

    return {
        work: function() {/* Function implementation. */},
        play: function() {/* Function implementation. */},
        size: 47
    };
});

Každý modul je zapísaný v samostatnom súbore vytvorený pomocou define, ktorému sa ako parameter zadá funkcia zodpovedná za pripravenie modulu. Samotný modul je hodnota navrátená z funkcie.

Môžeme si vyskúšať vytvoriť modul, ktorý už nejaké závislosti má.

//js/app/mysecondmodule.js
define(["jquery", "app/myfirstmodule"], function($, myfirstmodule) {
    //Do setup work here.

    return {
        color: "green",
        size: "large",
        show: function() {/* Function implementation. */}
    }
});

Ako prvý parameter sme tentoraz dali pole závislostí. Jednotlivé závislosti sú odovzdané ako parametre inicializačnej funkcii modulu, v našom prípade ako $ a myfirstmodule. Jednoduché a zábavné!

V tomto momente si možno kladiete otázku, ako requireJS vie, odkiaľ má zobrať jquery a myfirstmodule. Odpoveď je skrytá v konfigurácií.

//js/app.js
require.config({
    baseUrl: "/js",
    paths: {
        "jquery": "bower_components/jquery/jquery"
    }
});

require(["app/main"]);

RequireJS načítava dvoma nasledovným spôsobom:

  • Chceme načítať modul s názvom jquery, ktorý je definovaný v paths konfigurácií.
  • Url modulu sa vytvorí ako baseUrl + '/' + paths['jquery'] + '.js', v tomto konkrétnom prípade to je /js/bower_components/jquery/jquery.js. Treba si všimnúť, že na začiatok cesty bola pripojená hodnotabaseUrl a na koniec bola pridaná prípona súboru .js.

alebo druhým spôsobom

  • Chceme načítať modul s názvom app/myfirstmodule, ktorý nie je definovaný v paths konfigurácií.
  • Url modulu sa vytvorí ako baseUrl + '/' + "app/myfirstmodule" + '.js', teda /js/app/myfirstmodule.js. Opäť si všimnime, že .js je doplnené automaticky.

Ak názvy modulov končia príponou .js, alebo začínajú httpRequireJS odignoruje hore uvedené pravidlá a bude predpokladať, že sme mu uviedli priamo url k modulu. Nemusí byť vždy ľahké všimnúť si, že modulmyfirstmodule.js sa nenačítal preto, lebo sme v názve nechali .js.

Čo s cudzími knižnicami?

Žiaľ, väčšina cudzieho kódu, s ktorým prídeme do styku, nie je písaná v súlade s AMD. Pre tieto moduly vieme zapísať závislosti do konfigurácie nasledovne:

require.config({
    shim: {
        'backbone': {
            deps: ['underscore', 'json2', 'jquery'],
            exports: 'Backbone'
        },
        'underscore': {
            exports: '_'
        }
    }
});

Pripomeňme, že typická praktika neAMD knižníc je vytvoriť jeden globálny objekt a do neho zapísať svoj obsah. Property exports hovorí RequireJS, ako sa táto globálna premenná volá.

Použitie

Vieme, ako definovať závislosti. Pozrime sa teraz konečne na to, ako RequireJS použijeme na stránke.

Do nášho HTML kódu vložíme magický script tag, ktorý načíta RequireJS.

<!-- index.html --!>
<script data-main="js/app.js" src="js/bower_components/requirejs/require.js></script>

Atribút data-main určuje hlavný javascriptový súbor, ktorý sa ako prvý načíta. V tomto súbore by sa mala na začiatku nachádzať konfigurácia a neskôr načítanie hlavného modulu aplikácie. My obsah súboru js/app.jsukončíme príkazom require(['app/main']).

V súbore js/app/main.js načítame závislosti a nadefinujeme vstupný bod našej aplikácie (ako funkcia main v C/C++ alebo Jave).

//js/app/main.js
require("jquery", "app/myfirstmodule", function($, myfirstmodule) {
    //This is the main function.
    //Do stuff!
});

Typicky však nechceme spúšťať žiaden kód skôr, ako bude pripravený DOM. Jedna z možností je použiť klasické jQuery riešenie $(function(){}), alebo nainštalovať plugin requirejs-domready (bower install requirejs-domready).

Obe možnosti sú rovnako dobré, druhá sa trochu elegantnejšie používa. Stačí ako poslednú zo závislostí uviesť domready! s výkričníkom na konci a máme zaručené, že funkcia sa spustí až po pripravení celého DOMu.

//js/app/main.js
require("jquery", "app/myfirstmodule", "domready!", function($, myfirstmodule) {
    //This is the main function.
    //Do stuff!
});

Samozrejme, netreba zabudnúť pridať domReady do paths.

paths: {
    domready: "bower_components/requirejs-domready/domReady"
}

Na domácu úlohu

Tu možnosti RequireJS nekončia, občas treba rôznym knižniciam podhodiť ako ako závislosť rôzne verzie jednej knižnice, niekedy treba modul pred použitím inicializovať, inokedy chceme importovať aj iné zdroje ako javascript, prípadne by sme radi pred deployom celý kód efektívne minifikovali. Toto všetko RequireJS má a ponúka, no nezmestilo sa do tohto článku. Záujemcom o tieto pokročilé fičúrie odporúčam prečítať si oficiálnu dokumentáciu, ktorá je príjemne spracovaná.

Feedback prosím

Ohodnoťte prosím tento článok v ankete alebo v komentári pod článkom. Ďakujem, spätnú väzbu si veľmi cením!

Zdroje

Pri písaní som veľa čerpal z oficiálnej dokumentácie RequireJS, každému odporúčam preštudovať.

Dobrý článok? Chceš dostávať ďalšie?

Už viac ako 4 200 z vás dostáva správy e-mailom. Nemusíš sa báť, nie každé ráno. Len občasne.

I agree to have my personal information transfered to MailChimp ( more information )

Tvoj email neposkytneme 3tím stranám. Posielame naňho len informácie z robime.it. Kedykoľvek sa môžete odhlásiť.