Strange Case of Dr Jekyll

Stare porzekadło mówi, że lepsze jest wrogiem dobrego. Mając je sobie za nic, poświęciwszy na to niecałe 2 dni, wracam do podstaw, czyli do statycznych stron WWW. Jako kilkuletni bachor tworzyłem takie strony ręcznie, mimo że na podłączenie internetu w domu musiałem czekać jeszcze kilka lat. Dziś na szczęście nie muszę kodu strony wpisywać z palca - zrobi to za mnie Jekyll.

Migracja z Wordpressa

Jedną z zasad sztuki programowania w Uniksie jest to, że tekst jest uniwersalnym interfejsem1. Czy zatem najlepszym rozwiązaniem blogowym nie będzie system oparty po prostu na transformowaniu tekstu?

Jekyll w gruncie rzeczy właśnie tym jest - systemem transformującym wpisy zapisane w formacie Markdown2 do statycznych stron HTML opisanych przy pomocy szablonów Liquid. Oba formaty (tj. Markdown i Liquid) są - przynajmniej z perspektywy moich potrzeb - bardzo proste i intuicyjne w użyciu. Samo formatowanie Markdown używam już od jakiegoś czasu do zapisu większości prostych dokumentów tekstowych, które wymagają stylizacji. Nawet w Wordpressie zainstalowałem sobie w tym celu odpowiednią wtyczkę-filtr, chociaż gdy teraz o tym myślę, to jej architektura nie była zbyt przekonywująca: w pole edycji wpisu wklejało się tekst sformatowany w Markdown, wtyczka konwertowała go do HTML-a zapisywanego do bazy danych, a następnie pobierała go, rekonwertowała z powrotem do Markdowna, był wyświetlany w oryginalnym okienku edycji. Nietrudno sobie wyobrazić, że wyświetlony tekst był jakoś sformatowany - odbiegał on dość znacznie od oryginału, zgodnie z ograniczonymi możliwościami parsera Markdown zaimplementowanego we wtyczce.

Gdy więc kilka dni temu (dosłownie) po raz pierwszy usłyszałem o Jekyllu, od razu poczułem, że to jest to. Nie będę się w tym miejscu rozpisywał nad jego wszystkimi zaletami, gdyż powstało na ten temat kilka świetnych artykułów, które łatwo wyszukać wpisując w ulubioną wyszukiwarkę np. frazę Jekyll vs Wordpress, a ja sam w trakcie tego przydługiego artykułu z pewnością jeszcze zdążę wymienić kilka rzeczy, które mi najbardziej przypadły do gustu.

Oczywiście wszystko należy zacząć od instalacji Jekylla. Został on napisany w Rubym, więc można go zainstalować poprzez ściągnięcie odpowiedniej paczki Gem. Nie jestem wielkim fanem tego typu wynalazków z tego względu, że nie uważam, by mix managerów paczek prowadził do czegokolwiek dobrego. Na szczęście w repozytoriach Debiana znajduje się Jekyll w wersji 2.2.0 (nie jest to oczywiście najnowsza wersja, ale całkiem nieźle się spisuje), więc mogłem do jego instalacji z czystym sumieniem użyć apta.

Niestety, aby zaimportować wpisy z Worpressa, musiałem doinstalować Gema jekyll-import, którego już w repo Debiana nie było. Nie znam Ruby’ego, nie znam RubyGems, ale mogę śmiało powiedzieć, że jest to chyba jeden z najgorszych projektów jaki powstał.

Z początku nie działo się nic: komenda gem zostawiła mnie sam na sam ze znakiem zachęty, podłączony strace zwisł na jakimś wywołaniu waita, a ja się zastanawiałem, czy 30 sekund bezczynności to już nieskończoność, czy jeszcze nie. W końcu RubyGems odblokował się wypierdzielając się ptzy tym z komunikatem o błędzie, którego treść brzmiała mniej-więcej tak: “coś mi się chyba nie udało”. Po wklejeniu komunikatu błędu w wyszukiwarkę dowiedziałem się jednej rzeczy: większość osób, która spotkała się z tym błędem nie została wyposażona w ośrodek myślenia, gdyż wszyscy, jeden za drugim, sugerowali, jak mantrę, instalację pakietu ruby-dev (który oczywiście miałem zainstalowany). Żeby nie przedłużać tego, mam nadzieję, dość plastycznego opisu sytuacji, w końcu znalazłem gdzieś na dysku zapisany log z tego wspaniałego narzędzia i z niego dowiedziałem się, że gdzieśtam odpalana jest kompilacja normalnego języka, a gcc 4.8 nie wspiera po prostu jakiejś flagi budowania, którą któraś z paczek sobie naiwnie ustawiała. Szybkie update-alternatives i ustawienie gcc 4.9 jako systemowego uratowało sytuację i mogłem się cieszyć zainstalowanymi gdzieś (nie wiem dokładnie, gdzie) narzędziami, które miały mi umożliwić eksport/import mojej bazy danych.

I owszem - narzędzie to zaimportowało wszystkie moje wpisy, ale sposób, w jaki to zrobiło wołał o pomstę do nieba. W związku z tym najbliższe dwie-trzy godziny spędziłem na tworzeniu skryptu, który poprawił najczęstsze błędy importera. Następną godzinę zajęło mi ręczne nanoszenie kolejnych poprawek. Efekt jest jednak wart swojej ceny, gdyż mam teraz pięknie sformatowane, wersjonowane w Gicie archiwum wpisów.

Migracja wpisów to zaledwie krok pierwszy. Jako że nie chciałem rozstawać się z moim dotychczasowym szablonem (Twenty Twelve), musiałem go sportować do szablonu Liquid. Mając do podglądu źródła wygenerowanych przez Wordpressa stron, a także źródła PHP oryginału, zadanie uznaję za banalne, choć nieco czasochłonne3. Mam jedynie nadzieję, że nie pominąłem żadnego fragmentu umożliwiającego poprawne renderowanie się strony np. w IE7.

Workflow

Generację statycznych stron HTML w oparciu o utworzone szablony wykonujemy przy pomocy jekyll lub jekyll build. Sam Jekyll dostarcza się wraz z prostym serwerem HTTP zdolnym do lokalnego wyświetlenia naszego bloga pod adresem localhost:4000. Jest on również w stanie na bieżąco obserwować zmiany zawartości i aktualizować potrzebne pliki: jekyll serve -w. Gdy jesteśmy zadowoleni z tego co widzimy, katalog z wygenerowanymi plikami możemy wrzucić na prawdziwy serwer - ja mam to szczęście, że mogę wywołać rsynca, który zsynchronizuje mój katalog lokalny oraz jego zdalne alter ego:

rsync -vrzc --delete ./_site/ $DESTINATION

Tłumacząc z języka rsynca na ludzki: rekursywnie zostaną zaktualizowane te pliki z lokalnego katalogu _site, które mają inną sumę kontrolną niż ich zdalne odpowiedniki. Podczas deploymentu rsync będzie wysyłał pliki skompresowane, a wszystkie pliki zdalne, które nie mają swoich odpowiedników lokalnych zostaną usunięte. Oczywiście nie chcę podawać całemu światu informacji o serwerze, z którego korzystam i ścieżce do bloga, więc mam je zapisane jedynie w lokalnym pliku konfiguracyjnym, który profilaktycznie dodałem do .gitignore, aby uniknąć przypadkowego wysłania w eter lub usunięcia, jako że git clean -fd to komenda, którą wykonuję nader często. Oczywiście samo wywołanie rsynca jest owrappowane dodatkowym skryptem, który ma za zadanie upewnić się, że użytkownik nie jest pijany. A ponieważ moje palce same składają się w słówko make, wszystkie komendy dodałem pod odpowiednie targety w Makefile’u.

Jako że jedynym słusznym edytorem tekstu jest Vim4, zainstalowałem również wtyczkę Tima Pope’a, vim-liquid. Wspiera ona m.in. podświetlanie osadzonej składni YAML-a, Liquida. Dodatkowo stworzyłem skrypt generujący szablon dla nowych wpisów - ot tak, ze zwykłego lenistwa.

Czy jestem zadowolony? W życiu tak nie byłem! Chociaż początkowe postawienie Jekylla na nogi jest bardziej wymagające i czasochłonne niż analogiczna czynność w przypadku Wordpressa, to sama obsługa jest o niebo prostsza i znacznie bardziej intuicyjna5! I chociaż nie wszystko działa jeszcze jak należy6, a osobiście widziałbym kilka ulepszeń w samym Jekyllu7, to nie mogę narzekać, gdyż jego architektura sama zachęca do “dłubania” przy implementacji strony - uczucie programiście najmilsze, którego w przypadku stron opartych na Wordpressie chyba nigdy nie miałem.


  1. Applying the Unix Philosophy, Textuality 

  2. Domyślnie dostępnych jest kilka procesorów Markdown, a dodatkowo istnieje możliwość dodania własnych. 

  3. Chociaż więcej niż samo portowanie zajęło mi chyba szukanie, czy ktoś już takiego portu nie wykonał. 

  4. Co by Stallman nie mówił o swoim kościele, nie dajcie się zwieść! 

  5. Znacznie bardziej przypomina typowy sposób pracy: zrób jakieś zmiany lokalnie, wrzuć je do repo, zainstaluj repo na serwerze - do czegoś takiego jestem właśnie przyzwyczajony. 

  6. Tagi, czy, z oczywistych względów, wbudowana wyszukiwarka. 

  7. Chciałbym, żeby Jekyll udostępniał API np. w formacie JSON-a, gdyż nie znam i w tej chwili nie zamierzam poznawać Ruby’ego.