W dzisiejszym poście pociągnę zagadnienie gulpa. Jeśli nie czytałeś/czytałaś pierwszego wpisu z tej serii, zrób to teraz, gdyż to co ten wpis jest bezpośrednią kontynuacją.
Ostatnim razem przedstawiłem podstawy zarządzania gulpem. Pokazywałem jak stworzyć podstawowe zadania z użyciem tego narzędzia. Dziś opiszę dwa dodatkowe, równie przydatne, mechanizmy.
Zakładam, że stan projektu jest dokładnie taki sam jak zostawiłem go ostatnim razem. Znajdują się w nim trzy główne elementy. Dwa foldery src i dist oraz plik gulpfile.js.
Pierwszy folder zawiera nieprzetworzone, ‚surowe’ pliki źródłowe. Do drugiego folderu, trafia plik, który powstaje w wyniku wykonania zadań gulpa. Jego treść to połączony i zminifikowany kod plików znajdujących się w pierwszym folderze. W pliku gulpfile.js natomiast, znajduje się konfiguracja zadań gulpa. Zadania te napisane są oczywiście w języku JavaScript.
Oto jak wygląda obecny stan pliku gulpfile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
var gulp = require('gulp'); var concat = require('gulp-concat') var gulpTS = require('gulp-typescript'); var uglify = require('gulp-uglify'); gulp.task("typescript",function(){ return gulp.src('src/*.ts') .pipe(gulpTS({ noImplicitAny: true, out: 'funk.js' })) .pipe(gulp.dest('src')) }) gulp.task("concat", ["typescript"], function(){ return gulp.src('src/*.js') .pipe(concat('final.js')) .pipe(uglify()) .pipe(gulp.dest('dist')); }) |
Dzięki takiej konfiguracji, po wywołaniu zadania concat, gulp wykona najpierw zadanie typescript, ‚kompilujące’ plik .ts na javascript, a następnie za pomocą concat połączy wszystkie pliki w jeden i wyśle go do folderu dist (przy okazji minifikując treść wynikową 😉 ).
Problemem jednak było to, że zadanie typescript, pozostawiało po sobie plik, zawierający ‚tłumaczenie’ z typescriptu na JS. W idealnym świecie nie było by tego pliku, jest to w końcu artefakt procesu i nie chcemy aby pojawiał się w katalogu z kodem źródłowym. Dość popularnym rozwiązaniem jest tworzenie katalogu temp, do którego wrzuca się pliki tymczasowe. Ja jednak pokażę inny sposób.
Najpierw, trzeba w projekcie zainstalować dodatkowy moduł o nazwie event-stream. Dzięki niemu, będę miał trochę więcej opcji jeśli chodzi o zarządzanie potokami. Możliwości tego narzędzia są ogromne i zachęcam gorąco do zapoznania się dokumentacją. Ja tym razem skorzystam tylko z jednego mechanizmu.
Aby zainstalować moduł do projektu, wystarczy w konsoli wpisać:
1 |
npm install event-stream --save-dev |
Kiedy to jest już gotowe, mogę zmienić zawartość gulpfile. Tak będzie wyglądał nowy kod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var gulp = require('gulp'); var concat = require('gulp-concat') var gulpTS = require('gulp-typescript'); var uglify = require('gulp-uglify'); var es = require('event-stream'); gulp.task("concat", function(){ var ts = gulp.src('src/*.ts').pipe(gulpTS({noImplicitAny: true,out: 'funk.js'})); var js = gulp.src('src/*.js'); return es.merge(ts,js) .pipe(concat('final.js')) .pipe(uglify()) .pipe(gulp.dest('dist')); }) |
Najpierw dodaję do skryptu moduł event-stream. Jego zawartość trafia do zmiennej es. Dalej jest kilka zmian. Najważniejsze jest to, że nie ma już zadania typescript. Teraz wewnątrz zadania concat tworzę dwie zmienne ts oraz js. Tutaj wychodzi kolejne piękno stosowania potoków. Nie muszę zwracać ich w zadaniu, lub wysyłaniu ich do gulp.dest, mogę po prostu przypisać je do zmiennych.
Do zmiennej js przypisuję zawartość wszystkich plików znajdujących się w src, których rozwinięcie to js. Pliki te będą znajdować się w pamięci komputera, nigdzie nie jest tworzona ich ‚fizyczna’ kopia. Do zmiennej ts trafiają wszystkie pliki z rozwinięciem ts, które są na dodatek przepuszczone przez potok, tłumaczący typescript na ‚nasze’.
Przygotowane tak zmienne, mogę teraz wykorzystać przez moduł event-stream. Dokładnie to robię. Trafią one jako parametry do metody merge, tego modułu. Dzięki merge treść obu tych potoków jest łączona i przez kolejne potoki, traktowane są jak jedno.
Dalsze polecenia powinny być już oczywiste. Treści plików znajdujących się w potokach są łączone w final.js, minifikowane i zapisywane w folderze dist.
Teraz po wywołaniu zadania concat, otrzymam poprawny wynik a po projekcie nie będą walać się żadne nadprogramowe pliki. Idealnie.
Ale to nie jest jeszcze wszystko. Na sam koniec zostawiłem wisienkę, czyli gulpowe zadanie watch. Do tego nie muszę instalować żadnych dodatkowych modułów. Wszystko co potrzebuję jest dostępne w ‚rdzeniu’ gulpa. Do mojego pliku gulpfile.js, dopisuję taki kod:
1 2 3 |
gulp.task("watch", function(){ gulp.watch('src/*.{js,ts}', ['concat']); }); |
Jest to nowe zadanie o nazwie watch. W funkcji zawierającej treść zadania dodałem wywołanie metody watch obiektu gulpa. Metoda przyjmuje dwa argumenty. Pierwszy z nich wskazuje na pliki, która mają być obserwowane. W moim wypadku są to wszystkie pliki w katalogu src, ktorych rozwinięcie to ts lub js (mogę zdefiniować wybór za pomocą tej składni z ‚wąsatymi’ nawiasami). Drugi argument, to tablica zawierająca nazwę zadania, które zostanie wykonane gdy któryś z wpisanych wcześniej plików zostanie zmieniony. Dodanie do projektu nowego pliku pasującego do wzoru, również wywoła to zadanie.
Teraz wystarczy odpalić w konsoli zadanie watch. Uruchomi się proces, który będzie trwał dopóki okno konsoli jest otwarte. Gdy wykryta zostanie zmiana w zaznaczonych plikach, proces wywoła zadanie concat. I to jest już idealne ustawienie projektu. Przynajmniej na początek 😉 .
Wiadomo, dotykam tu tylko wierzchołka góry lodowej, ale te podstawy powinny wystarczyć dla pierwszych projektów. Dają one naprawdę sporo możliwości. Zachęcam do zgłębiania tematu na własną rękę, przeszukujcie neta lub dokumentacje modułów. Serio, jeżeli wydaje Ci się, że coś w twoim projekcie można by było zautomatyzować, na pewno jest już moduł gulpa, który to robi 🙂 .
I to tyle na dziś. Tymczasem, jak zawsze, zachęcam do polubienia mojej strony na facebooku. Zawsze na bieżąco zamieszczam tam informacje o nowościach, więc warto polubić aby nie przegapić żadnego nowego wpisu.
kolejny mega przydatny i interesujący wpis, dzięki!
Wow, ale miło. Fajnie wiedzieć, że komuś się przydaje moja twórczość 😉
I to bardzo przydaje. Piszesz w bardzo przystępny sposób, przykłady dajesz takie, które pozwalaja dobrze zrozumieć zaganienie, dzięki temu w ekspresowym tempie dzięki Tobie można przerobić podstawy wielu nowych technologii. I, to już pewnie Twoja osobia cecha, pieszesz w bardzo naturalny sposób, bez bufonady która często zieje z tekstów innych programistów. Także dzięki za te masę wpisów jeszcze raz.
Jeśli mogę zasugerowac jakieś kolejne tematy to ciekawym by było np. reactjs, ES6 (i może powiązanie tego z wpisami o TS), może tworzenie boilerplatów w nodejs (takich paczek startowych do noda do tworzenia apek webowych z konfiguracją serwera, bundlowaniem, autoreloadem przeglądarki, zadaniami gulpa itp). Myślę, że takie wpisy byłby taką właśnie dobrą kontynuacją wcześniejszych postów które układają się w cały taki ciąg który można by nazwać „Moder JS” 🙂
Faktycznie, dobre tematy. Rozważałem już niektóre z nich. Informacji do przekazania jest naprawdę sporo, szkoda, że czasu tak mało 🙂 Zobaczymy co uda się wrzuć.
Ladnie opisane.
Jedno mnie tylko zastanawia. Po co w ogole ten caly gulp i dodatki. Tylko dlatego ze da sie to zrobic w js?
W celu automatyzacji mozna zdefiniowac dowolna ilosc dowolnych zadan w pliku makefile i wywolac make i to niezaleznie od uzywanego jezyka programowania.
Make jest „inteligentne” i wykonuje operacje tylko na tych zadaniach ktorych kod zrodlowy faktycznie zmienil sie oraz pilnuje zaleznosci nie pozwalajac zeby jakis plik sie zagubil. Przy duzych projektach jest to naprawde istotne.
Make jest malutkie, szybkie i banalne w konfiguracji oraz bezbledne poniewaz jest juz uzywane wiele dekad.