Da ich auf meinem Blog wirklich selten etwas schreibe, war mir Wordpress schon lange ein Dorn im Auge. Deshalb habe ich mich in den letzten Wochen bemüht, meine Website auf Jekyll umzustellen. Jekyll ist ein statischer Seitengenerator, der auch Blogs verwalten kann. Jekyll ist in Ruby entwickelt und daher auch als Ruby-Gem verfügbar.

Installation

Ich wollte von Anfang an, dass die Build-Umgebung portabel ist, auch z.B. in einer CI/CD-Pipeline. Deshalb habe ich mich entschieden, jekyll und seine Abhängigkeiten nicht aus einem Systempaket zu installieren, sondern die entsprechenden Pakete mit Bundler aus den Gems zu laden.

Dazu habe ich ein neues Verzeichnis www.fusselkater.org angelegt und dort bundle init ausgeführt. Damit der Bundler in den nächsten Schritten nicht versucht, die benötigten Gems systemweit zu installieren, habe ich danach noch .bundle als Pfad gesetzt:

bundle config set --local path '.bundle'

Die Installation von Jekyll erfolgt dann über bundle add jekyll. Dieser Befehl schreibt jekyll auch direkt in das durch bundle init erzeugte Gemfile, so dass später nur noch bundle install aufgerufen werden muss, um die Build-Umgebung aufzubauen.

Neues Jekyll-Projekt erstellen

Da Jekyll im .bundle Pfad installiert wird, ist der Befehl jekyll natürlich nicht in den Systempfaden enthalten. Um die über Bundler installierten Programme trotzdem nutzen zu können, kann man einfach ein bundle exec vor den entsprechenden Befehl setzen.

bundle exec jekyll new src --blank

Da ich nicht das Standard Minima-Theme haben wollte, habe ich das Jekyll-Projekt mit dem Parameter --blank erstellt. Dies sorgt dafür, dass nur das Gerüst für eine Jekyll-Webseite aufgebaut wird.

Themes

Für Jekyll gibt es zahlreiche Themes. Leider lassen sich die meisten Themes nicht über Gems installieren, sondern erwarten, dass man ein Jekyll-Projekt forkt und in seine Webseite einbaut. Das fand ich sehr unsauber, weshalb ich mich bei der Theme-Auswahl auf solche Themes beschränkt habe, die via Gem verfügbar sind.

Meine Wahl fiel schließlich auf das whiteglass Theme, welches ich dann mittels bundle add jekyll-whiteglass installierte.

In der Installationsanleitung des Themes wird auch beschrieben, dass noch einige Dateien aus dem Github Repository installiert werden müssen. Dies habe ich entsprechend gemacht:

pushd src
rm index.md
curl -L -O "https://github.com/yous/whiteglass/raw/master/{index.html,about.md,archives.md,feed.xml,robots.txt}"
curl -L --create-dirs -o _data/#1 "https://github.com/yous/whiteglass/raw/master/_data/{navigation.yml,i18n.yml}"
popd

Später habe ich die Datei about.md in gpg.md umbenannt, um eine Seite für meinen GPG-Schlüssel zu erstellen und die Datei _data/naviagion.yml entsprechend angepasst.

Plugins

Zum Aufbau der Seite werden noch einige Plugins benötigt. Deshalb habe ich einige Plugins mit bundle add installiert:

bundle add --group jekyll_plugins jekyll-archives jekyll-paginate jekyll-sitemap jekyll-feed

Im weiteren Verlauf ist mir aufgefallen, dass es mit Jekyll standardmäßig nicht möglich ist, Bilder, die in den einzelnen Blogartikeln verwendet werden, im Ordner des jeweiligen Blogartikels zu speichern, sondern dass diese immer im globalen Ordner assets abgelegt werden müssen. Da ich befürchtete, dass dies später im Chaos enden würde, habe ich nach einer Lösung gesucht und das Plugin jekyll-postfiles gefunden. Dieses kopiert während des Build-Prozesses die statischen Daten aus den Ordnern der Blog-Artikel in die Assets.

bundle add --group jekyll_plugins jekyll-postfiles

Erster Test

Nun war alles bereit, um den Entwicklungsserver zu starten:

pushd src
bundle exec jekyll serve
popd

Das funktionierte wunderbar. Das Grundgerüst für die neue Seite stand also.

Makefile

Da mir das ständige Wechseln zwischen den Verzeichnissen und das Merken der Befehle langsam lästig wurde, habe ich mir ein Makefile geschrieben, das mir diese Arbeit abnimmt:

.DEFAULT_GOAL:=help

BUNDLE = bundle
SRCDIR = src
DSTDIR = out

MINIFY_HTML = bin/minify-html
MINIFY_HTML_URL = https://wilsonl.in/minify-html/bin/0.11.1-linux-x86_64

.PHONY: help
help: ## Display this help message
	@echo 'Usage: make <command>'
	@cat $(MAKEFILE_LIST) | grep '^[a-zA-Z]'  | \
	    sort | \
	    awk -F ':.*?## ' 'NF==2 {printf "  %-26s%s\n", $$1, $$2}'

.PHONY: setup
setup: ## Install requirements
	${BUNDLE} config set --local path '.bundle'
	${BUNDLE} install
	mkdir -p bin
	curl ${MINIFY_HTML_URL} -o ${MINIFY_HTML}
	chmod +x ${MINIFY_HTML}

.PHONY: serve
serve: ## Start the development server
	${BUNDLE} exec jekyll serve --source ${SRCDIR} --destination ${DSTDIR}

.PHONY: build
build: ## Build the site for production (minify HTML/CSS/JS)
	${BUNDLE} exec jekyll build --source ${SRCDIR} --destination ${DSTDIR}
	${MINIFY_HTML} \
		--keep-closing-tags \
		--minify-css \
		--do-not-minify-doctype \
		--ensure-spec-compliant-unquoted-attribute-values \
		--keep-spaces-between-attributes \
		$$(find ${DSTDIR} -type f -iname '*.html' -o -name '*.css' -o -name '*.js')

.PHONY: clean
clean: ## Cleanup output and temporary files
	rm -rf ${DSTDIR}
	rm -rf ${SRCDIR}/.jekyll-cache

Zusätzlich habe ich auch direkt einen HTML-Minifier in das Build-Target geschrieben, so dass die HTML-, CSS- und JS-Dateien nach dem Bau der produktiven Seite verkleinert werden.

Google Fonts

Das whiteglass-Theme verwendet standardmäßig den Bitter-Font direkt von Google. Da mir das datenschutztechnisch nicht gefällt, habe ich mich nun darum gekümmert, den Bitter-Font auf meinem Host anzubieten. Dazu habe ich den Bitter-Font heruntergeladen und die beiden Dateien Bitter-Italic-VariableFont_wght.ttf und Bitter-VariableFont_wght.ttf in das woff2-Format konvertiert.

woff2_compress Bitter-Italic-VariableFont_wght.ttf
woff2_compress Bitter-VariableFont_wght.ttf

(Das Programm woff2_compress ist im Paket woff2-tools (Fedora) enthalten)

Die beiden woff2-Dateien habe ich nun nach src/assets/fonts/Bitter/italic.woff2 bzw. src/assets/fonts/Bitter/regular.woff2 kopiert.

Im nächsten Schritt war es notwendig, einige Dateien aus dem Theme zu überschreiben. Dazu habe ich folgende Dateien erstellt:

src/_includes/fonts.html:

<link href="/assets/fonts/Bitter/fonts.css" rel="stylesheet">

src/assets/fonts/Bitter/fonts.css:

  /* latin */
  @font-face {
    font-family: 'Bitter';
    font-style: italic;
    font-weight: 400;
    src: url(/assets/fonts/Bitter/italic.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
/* latin */
@font-face {
    font-family: 'Bitter';
    font-style: normal;
    font-weight: 400;
    src: url(/assets/fonts/Bitter/regular.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
/* latin */
@font-face {
    font-family: 'Bitter';
    font-style: normal;
    font-weight: 700;
    src: url(/assets/fonts/Bitter/regular.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }

Blog-Einträge

Nun war alles bereit, um meine Blogeinträge aus Wordpress zu kopieren. Da ich nur 2 Blogeinträge hatte, habe ich das manuell gemacht. Es gibt aber ein [Projekt] (https://github.com/benbalter/wordpress-to-jekyll-exporter), das das automatisiert.