Jak zacząć z Angular 2?

Na potrzeby konkursu DSP2017 buduję aplikację LocalVan. Postanowiłem więc przy okazji przebadać od podstaw bibliotekę Angular 2. Ma to na celu utrwalenie zdobytej przeze mnie całkiem niedawno wiedzy oraz być może ułatwić komuś innemu życie.

Więc jak żyć Panie Google? To pytanie zadawałem sobie jeszcze jakiś czas po tym jak zacząłem pracować z tytułową biblioteką. Moim zdaniem wielu użytkowników ma podobne odczucia, zwłaszcza jeżeli podobnie jak ja zaczynali od głównej dokumentacji i wprowadzenia. W skrócie brzmi to tak: „Zainstaluj ten przykładowy projekt, uruchom skrypt i odpal przeglądarkę. Za wszelką cenę nie pytaj dlaczego ładujemy tutaj 30 plików i 100 MB innych bibliotek pokrewnych.”
No i rzeczywiście, można z powodzeniem rozwijać aplikację z przykładowego repozytorium i nigdy nie dowiedzieć się co i dlaczego. Jak się okazuje tu nie ma żartów, bo angular w wersji drugiej wykorzystuje mnóstwo zewnętrznych narzędzi więc żaden szanujący się developer raczej nie zbuduje aplikacji na podstawie tysięcy linijek kodu o nieznanym mu sposobie działania i zagadkowym pochodzeniu. Podkreślam tu stwierdzenie „szanujący się”. 🙂

Postanowiłem więc przyjrzeć się co jest grane i rozbić to na mniejsze, możliwie zrozumiałe kroki. Logicznym wydaje mi się zacząć od samego kodu źródłowego. Niech nasza przykładowa aplikacja ma za zadanie wyświetlać napis „Hello LocalVan”.

Kod źródłowy tworzyć będę w języku TypeScript, ponieważ taki właśnie sposób promują twórcy biblioteki. Pozwala nam to wykorzystywać funkcjonalności najnowszych standardów JavaScript bez żadnych skrupułów.
W folderze projektu tworzymy nowy folder ‚app’ a w nim dwa widoczne powyżej pliki *.ts. Jeden z nich to definicja modułu a drugi to prosty komponent zawarty w module. Moduły służą logicznemu grupowaniu komponentów dotyczących na przykład tej samej funkcjonalności w aplikacji. Ich drugim zastosowaniem jest optymalizacja, ponieważ dzięki takiemu podziałowi angular załaduje tylko naprawdę aktualnie potrzebne moduły zamiast całego kodu.

Co jeszcze ciekawego widać w tym kroku? Przede wszystkim słowo kluczowe ‚import’. Jest to polecenie ze standardu ECMAScript 2015 (es6), który na dzień dzisiejszy nie jest zaimplementowany w praktycznie żadnej przeglądarce. Import służy do dynamicznego ładowania dowolnej funkcji czy zmiennych z podanego pliku. W tym wypadku ładujemy ‚NgModule’ z paczki @angular/core oraz ‚BrowserModule’ z paczki @angular/platform-browser. Importujemy również nasz własny ‚AppComponent’ z odpowiedniego pliku. Ten zaś importuje ‚Component’ z angulara, który jako dekorator służy do opisywania tworzonych komponentów. Pozwala on na nieco więcej, ale na ten moment ograniczam się do selektora, czyli nazwy znacznika, który wywoła nasz komponent w dokumencie HTML oraz szablonu naszego komponentu, czyli części wizualnej. Na ten moment ‚AppComponent’ będzie zwykłym napisem. Na koniec ‚exportujemy’ nasz komponent. Jest to znów element standardu es6, który służy do wystawiania funkcji/zmiennych na zewnątrz, dzięki czemu możemy je później importować w innych plikach. Proste?
W definicji modułu (app.module.ts) sprawy mają się podobnie, ale zamiast definicji komponentu definiujemy używane moduły oraz określamy ‚bootstrap’, czyli komponent startowy. Jest to o tyle istotne, żeby nasza aplikacja miała jakiś punkt startowy. Na koniec podobnie, exportujemy klasę modułu na zewnątrz. Tworzymy teraz plik Main.ts, który będzie głównym skryptem aplikacji, którego zadaniem będzie załadowanie pozostałych.

Tutaj importujemy ‚platformBrowserDynamic’ z angulara oraz nasz moduł z odpowiedniego pliku. Ten pierwszy pozwoli nam odpalić (ang. ‚bootstrap’) go na starcie aplikacji. Ten zaś jak wspomniałem wyżej, będzie już wiedział, że domyslnym komponentem jest ‚AppComponent’. Bardzo ważne jest rozumienie różnicy pomiędzy modułem a komponentem, bo inaczej cały proces może się wydawać wybitnie niejasny.
To by było na tyle, jeżeli chodzi o kod źródłowy. Używanie TypeScript i niezaimplementowanych jeszcze w przeglądarkach standardów JavaScript powoduje, że nasz kod trzeba przetłumaczyć na coś zrozumiałego dla przeciętnej przeglądarki. Mowa tu o standardzie es5.

TypeScript najwygodniej konfiguruje się tworząc plik .json, który zawiera wszystkie niezbędne nam ustawienia. Czyli kompilujemy jak wspomniałem do es5. CommonJS, to popularny sposób definiowania modułów JS, którego zadaniem jest zapewnienie, że kod każdego z nich jest bezpiecznie zamknięty w jego obrębie i dwa moduły nie mogą się „zazębić”, czyli np. nadpisywac swoich zmiennych czy funkcji. ModuleResolution ustawiony na wartość ‚node’ określa sposób ładowania modułów, zbliżonego do sposobu w jaki działa NodeJS. Możemy wybrać czy chcemy generować ‚sourceMaps’, czyli pliki map używany do debuggowania kodu (możemy dzięki temu wiedzieć dokładnie w której linijce kodu TypeScript wystąpił błąd, nawet jeżeli przeglądarka posiada tylko plik .js i odpowiednią mapę). O pozostałych opcjach można poczytać w dokumentacji TypeScript jak np. niezbędne nam ‚decorators’ używane przez angular2. (np. @Component, @Module).

Chciałbym powiedziec, że to już koniec ale to ledwie połowa drogi do sukcesu. Co prawda możemy już spróbować uruchomić w konsoli polecenie:
tsc -p tsconfig.json
…ale nie zakończy się ono sukcesem. Jak widać na wcześniejszych listingach, używaliśmy mnóstwo elementów z paczek @angular, ale przecież nigdzie ich jeszcze nie wstawiliśmy. Musimy je więc pobrać. Oczywiście potrzebny jest też TypeScript i widoczna w linii poleceń komenda tsc. (skrót od: TypeScript Compiler)
Jak to zwykle w projektach JS, z pomocą przychodzi NPM. (może być też Yarn, który osobiście polecam). Tworzymy lub generujemy plik ‚package.json’:

Wymazałem na razie paczki, które nie są na tym etapie potrzebne. Używamy trzech paczek z @angulara czyli common, compiler i core. Brzmią jak coś potrzebnego więc nie wnikamy dlaczego aż trzy. Czym jest natomiast Platform Browser? Otóż angular 2 został zaprojektowany z myślą o wielu platformach, np. mobile. Od platformy zależy więc sposób rozruchu aplikacji (ang. bootstrap) i w przypadku aplikacji webowej potrzebujemy do tego przeglądarki. Paczka ta zawiera więc funkcje niezbędne do uruchomienia naszego programu właśnie w przeglądarce internetowej. Dlaczego dwie paczki? Tak naprawdę na tym etapie przydatny będzie tylko ‚-dynamic’, ponieważ moduły będą doładowywane na bieżąco gdy są potrzebne. Jest to sposób kompilacji zwany JIT (Just In Time) czyli po polsku „w samą porę”. Moduł jest potrzebny więc jest przesyłany. Drugi, alternatywny sposób kompilacji to AOT (Ahead Of Time) czyli „z góry/przed czasem” gdzie cała aplikacja jest składana w jeden plik i całość kodu jest dostępna od razu, bez potrzeby doładowywania żadnych plików. Nie jest to jednak koncept wprowadzony przez Angular 2 więc na pewno wielu programistów doskonale wie o co chodzi.

Ruszamy więc polecenie: ‚npm install’ i pobieramy wszystkie cenne moduły. W tym momencie TypeScript powinien z powodzeniem skompilować kody źródłowe do odpowiednich plików .js. Żeby nie było za łatwo pozostaje jeszcze jeden, ostateczny krok, czyli uruchomienie samej aplikacji w przeglądarce, ale to będzie temat kolejnego wpisu.

p.s. Jeżeli nie udało Ci się skopiować kodu z wstawionych przeze mnie screenów to zapraszam do repozytorium projektu, gdzie możesz eksperymentować z kodem do woli.