Wieści z frontu: Angular 2 i webpack — lepsze komponenty
Angular 1,5 a następnie 2.0 wprowadził do swojego frameworka koncepcję komponentów. Od tego czasu koncepcja ta mocno weszła w codzienne życie developerów frontendowych. Ja się do takich nie zaliczam, ale coś tam czasem "na froncie" robię i jest pewna rzecz, która irytowała mnie od zawsze.
Kiedy tworzymy komponent, robimy to w ten sposób, żeby był on możliwie generyczny i autonomiczny. Prawda? Dla przykładu, gdybyśmy tworzyli komponent wizytówki użytkownika, przekazywalibyśmy go zapewne z zewnątrz, a nie pobierali w komponencie. Stworzylibyśmy swój własny template i pliczek ze stylami.
Z resztą co tu dużo mówić. Wykorzystajmy angular cli i zobaczmy "co on na to".
ng generate component card
i mamy strukturę:
No i fajnie. Wszystko zamknięte w jednym miejscu. Style, html, logika. Super - możemy rozwijać nasz komponent niezależnie. Tak? A czego jeszcze możemy potrzebować? Różnego rodzaju resourców. Jakieś tło ładne, obrazek w html-u itd. I tu zaczynają się schody, bo chcąc dodać jakiś "asset"od razu strzelamy sobie prosto w stopę i wychodzimy poza naszą ładną strukturę komponentu.
Dzieje się tak, ponieważ ścieżki do zasobów nie są relatywne- musimy się odnieść do korzenia projektu.
W scss będziemy mieli coś takiego:
background: url(/assets/bg.jpg) no-repeat center center fixed;
a w html:
<img src="/assets/logo.png"/>
aby zachować jakiś podział zasobów, być może odwzorujemy w katalogu assets strukturę komponentów. No i mamy "ładne" rozproszenie informacji.
Możemy to tak zostawić, albo próbować coś z tym zrobić. Ja jednak powalczę. W standardzie z angularem 2 dostaliśmy webpacka. wykorzystajmy jego możliwości.
Zastanówmy się do czego dążymy Chcemy zamiast :
background: url(/assets/bg.jpg) no-repeat center center fixed;
mieć:
background: url(./resources/bg.jpg) no-repeat center center fixed;
a zamiast
<img src="/assets/logo.png"/>
mieć:
<img src="./res/logo.png"/>
i NAPRAWDĘ zamknąć komponent w jednym miejscu. Ok. to zacznijmy od sassów. Tu z pomocą przyjdzie nam resolve-url-loader.
https://www.npmjs.com/package/resolve-url-loader
zainstalujemy ten loader, a następnie dokonfigurujemy webpacka..... no tak, a gdzie webpack.config.js? Nie ma. Na szczęście możemy wyciągnąć skrypty i configi poleceniem:
ng eject
OK. skoro mamy nasz plik konfiguracyjny, dla plików scss dodajemy nasz loader ( po sass-loaderze)
Po dododaniu konfiguracji powinno się nam udać załadować pliki lokalne z poziomu sassa.
Musimy jeszcze coś zrobić z HTML-em. Tu z kolei mamy wbudowany template engine z angulara 2- nie wstrzykniemy tam rozwiązywania ścieżek relatywnych. Ale możemy go zastąpić html loaderem. https://github.com/webpack-contrib/html-loader
Podobnie jak poprzednio, musimy go zainstalować i skonfigurować webpacka. Zamienimy w tym celu raw loader na html loader w pliku webpack.config.js.
Ale niestety to nie wszystko. Musimy jeszcze zmienić sposób ładowania templateów html.
w tym celu użyjemy (niestety) webpackowego "require".
do tego to się sprowadza w kodzie:
Zamiast
@Component({ selector: 'app-first-page', templateUrl: './first-page.component.html', styleUrls: ['./first-page.component.css'] })
będziemy mieli
@Component({ selector: 'app-first-page', template: require('./first-page.component.html'), styleUrls: ['./first-page.component.css'] })
Oczywiście typescript "powie" nam że nie wie co to znaczy "require" Poprawmy to. W tym celu w katalogu src dodamy plik declarations.d.ts z następującym wpisem:
declare function require(string: string): string;
no i powinno działać. Teraz mamy prawdziwie zamkniety komponent. Oczywiście nic nie stoi na przeszkodzie, żeby nadal korzystać z globalnych assetów. Jest to wskazane w wielu wypadkach oczywiście. Ale często także bedziemy tworzyć komponenty, w któych będziemy wykorzystywać "prywatne" zasoby. Ot coś ala enkapsulacja.
Wbijaj na githuba i polookaj jak to wygląda w całości.