Skip to content
← Wszystkie wpisy
4 min czytania Dawid Skłodowski

Blog programisty z Jekyllem i GitHub Pages

Dlaczego strona statyczna to właściwe narzędzie na blog programisty i jak zbudować go z Jekyllem oraz hostować za darmo na GitHub Pages — front matter, layouty Liquid, posty w Markdownie i pisanie w tym samym workflow, którego już używasz do kodu.

Jeśli jesteś programistą, który chce bloga, odruchem jest sięgnięcie po WordPressa — i to zły odruch. Blog jest w istocie stertą artykułów i odrobiną nawigacji. Nie potrzebuje bazy danych, środowiska PHP, strony logowania ani łatki bezpieczeństwa co drugi tydzień. Potrzebuje renderować się szybko, nigdy nie padać, nic nie kosztować i pozwalać ci pisać tak, jak już pracujesz. Dokładnie to daje generator stron statycznych, a dla ekipy Ruby oznacza to Jekylla na GitHub Pages.

Zbudowaliśmy nasz blog tak i ten układ ma szczególną elegancję: twoje pisanie żyje w tym samym repozytorium git, w tym samym workflow Markdown-i-tekst, co kod, który piszesz cały dzień. Oto jak to się składa.

Dlaczego statycznie i dlaczego ten stos

Generator stron statycznych bierze szablony i pliki treści i kompiluje je, raz, w czysty HTML, CSS i JavaScript. Nie ma kodu po stronie serwera w czasie żądania — odwiedzający dostaje wcześniej zbudowany plik. Konsekwencje to same plusy dla bloga:

  • Jest praktycznie nie do zhakowania. Nie ma bazy do wstrzyknięcia, panelu admina do złamania brute-force, wtyczki z CVE. Powierzchnia ataku folderu plików HTML jest bliska zeru.
  • Jest szybki i tani. Pliki statyczne trywialnie się cache’uje i serwuje; CDN albo GitHub Pages dostarcza je natychmiast, za darmo, przy dowolnym ruchu.
  • Wersjonuje się jak kod. Posty to pliki w gicie. Masz historię, diffy, gałęzie i pull requesty na swoim pisaniu — napisz post na gałęzi, zrób review, zmerguj, by opublikować.

Jekyll to kanoniczny wybór w Ruby i — co kluczowe — GitHub Pages buduje go za ciebie natywnie. Wypchnij Markdown do repozytorium, a GitHub kompiluje i hostuje stronę automatycznie. Żadnego serwera build, żadnego skryptu deploy.

Kształt strony Jekylla

Projekt Jekylla to garść konwencji. Ważne elementy:

_config.yml        # ustawienia całej strony
_layouts/          # szablony HTML (default.html, post.html)
_includes/         # reużywalne wycinki (nagłówek, stopka)
_posts/            # twoje artykuły, jeden plik Markdown każdy
index.html         # strona główna
assets/            # CSS, obrazy, JS

Konwencją, która liczy się najbardziej, jest _posts/. Post to plik Markdown nazwany datą i slugiem — 2014-10-15-moj-pierwszy-post.md — a Jekyll czyta datę i tytuł wprost z tej nazwy pliku i jego nagłówka.

Front matter i Markdown: sam post

Każdy plik treści zaczyna się od bloku „front matter” w YAML między potrójnymi myślnikami, po którym następuje treść w Markdownie:

---
layout: post
title: "Dlaczego przeszedłem na Jekylla"
date: 2014-10-15
tags: [jekyll, blogowanie]
---

Oto **właściwy post**, napisany w Markdownie. Bloki kodu po prostu działają:

    def hello
      puts "world"
    end

Tak samo jak linki, listy i obrazy — rzeczy, z których zbudowany jest post
programisty.

Front matter to metadane, których Jekyll używa do wyrenderowania strony: layout wybiera szablon, który ją owija, title, date i tags są dostępne szablonom jako zmienne. Treść to czysty Markdown — i o to chodzi. Piszesz post w tym samym lekkim markupie, którego już używasz w README i pull requestach, we własnym edytorze, bez WYSIWYG-a walczącego z tobą o zabłąkany tag <p>.

Liquid: szablony i pętle

Jekyll renderuje szablony Liquidem, małym, bezpiecznym językiem szablonów. Layout owija twoją treść i wciąga metadane; pętla buduje twój indeks z kolekcji postów:

<!-- _layouts/post.html -->
<article>
  <h1>{{ page.title }}</h1>
  <time>{{ page.date | date: "%-d %B %Y" }}</time>
  {{ content }}
</article>
<!-- index.html: wymień każdy post, najnowsze pierwsze -->
<ul>
{% for post in site.posts %}
  <li>
    <a href="{{ post.url }}">{{ post.title }}</a>
    <span>{{ post.date | date: "%Y-%m-%d" }}</span>
  </li>
{% endfor %}
</ul>

{{ ... }} wypisuje wartość, {% ... %} to tag (sterowanie przepływem), a | stosuje filtr — tu date formatuje znacznik czasu. site.posts to kolekcja, którą Jekyll buduje z twojego folderu _posts/, posortowana od najnowszych. Te kilka linijek to cała twoja strona główna i pozostaje poprawna na zawsze: napisz nowy plik posta, a pojawi się na liście automatycznie.

Lokalny podgląd i publikacja

Uruchamiasz stronę lokalnie dokładnie tak, jak będzie serwowana:

gem install jekyll
jekyll serve            # buduje stronę i serwuje na localhost:4000, z live-reload

Edytuj plik Markdown, zapisz, odśwież — ta sama ciasna pętla, którą masz przy pracy nad kodem. Publikacja to po prostu git:

git add _posts/2014-10-15-moj-pierwszy-post.md
git commit -m "Nowy post: dlaczego przeszedłem na Jekylla"
git push origin gh-pages     # GitHub Pages buduje i wdraża automatycznie

Wypchnij na gałąź Pages, a twój post jest na żywo w niecałą minutę, serwowany z infrastruktury GitHuba bez kosztu. Skieruj własną domenę plikiem CNAME, a masz prawdziwy blog na własnym URL bez płacenia za czy utrzymywania choć jednego serwera.

Uczciwe kompromisy

Statyczność nie jest wolna od kosztów, to po prostu inny ich zestaw. Komentarze potrzebują usługi od strony trzeciej (Disqus i spółka), bo nie ma backendu — choć na blogu programisty wielu ludzi chętnie w ogóle pomija komentarze. Cokolwiek naprawdę dynamicznego — wyszukiwanie, formularze, personalizacja — musi być zrobione po stronie klienta albo oddane usłudze zewnętrznej. A build jest z wyprzedzeniem, więc strona z tysiącem postów chwilę się kompiluje (rzadko problem przy skali bloga).

Nic z tego nie przeważa zysków dla tego przypadku użycia. Dla bloga programisty podejście statyczne jest niemal idealnie dopasowane do zadania: twoje pisanie żyje obok twojego kodu, w gicie, w Markdownie; publikuje się przez git push; jest szybkie, darmowe i bezpieczne z konstrukcji; a całość to czyste pliki, które w pełni rozumiesz i posiadasz. Nigdy nie żałowaliśmy tego wyboru, a jedynym utrzymaniem przez lata było napisanie kolejnego posta.