sasswatch: Automatisches Kompilieren von SASS-Dateien per Dienst unter Gentoo Linux

Veröffentlicht als Einblick
von Joschi Kuphalam

In der Theorie waren mir CSS-Präprozessoren wie LESS und SASS schon eine ganze Weile bekannt – und irgendwie auch grundsätzlich sympathisch. Konzepte wie Variablen und Mixins leuchten sicher nicht nur mir gerade für die CSS-Entwicklung sofort ein. Und trotzdem hat es ziemlich lange gedauert, bis ich mich nun ernsthaft mit SASS (und Compass, der zugehörigen Baustein-Bibliothek) beschäftigt habe. Warum? Weil sich mir nicht so ohne Weiteres erschlossen hat, wie sich die Technik in meinen persönlichen Workflow integrieren lässt, ohne mir in der täglichen Anwendung zur Last zu fallen.

Für Webprojekte nutze ich in erster Linie eine Entwicklungsumgebung auf Eclipse-Basis. Das Aptana Studio Plugin für Eclipse bietet zwar angeblich Unterstützung für die SASS-Entwicklung, doch abgesehen von einem hochoffiziellen Editor für SASS-Dateien (der jedoch offenbar nicht nur mir keinerlei Content Assist bietet – was soll das Ganze dann?) konnte ich bisher keinen realen Nutzen darin entdecken. Vor allem aber: Mindestens ebenso wichtig wie ein vernünftiger Editor scheint mir die Unterstützung für eine automatische Kompilierung von SASS-Quelldateien in die resultierenden CSS-Dateien. Nach jeder winzigen Änderung einen Kompilierprozess manuell anstossen zu müssen wäre einfach weltfremd ...

Ant to the rescue?

Wie so oft präsentiert sich Eclipse glücklicherweise auch in diesem Fall grundsätzlich recht kooperativ, und es lässt sich mit Hilfe von Apache Ant ein entsprechender Workflow implementieren, so dass Änderungen an SASS-Dateien automatisch zur Aktualisierung der resultierenden CSS-Dateien führen. Die Einrichtung dieser Lösung ist im Wesentlichen hier beschrieben, wobei ich im ersten Anlauf einige Problemchen zu überwinden hatte. Kleiner Tip: Wer – wie ich – eine Einrichtung unter Windows versucht, sollte unbedingt sicherstellen, dass im Ant build file als "executable" sass.bat respektive compass.bat steht (statt nur sass bzw. compass) und dass das Verzeichnis dieser beiden Stapelverarbeitungsdateien in der PATH-Umgebungsvariable enthalten ist, so dass sie systemweit ohne absolute Pfadangabe aufgerufen / gestartet werden können.

Wenngleich auch die beschriebene Ant-Lösung grundsätzlich funktioniert, so finde ich sie nicht besonders praktikabel. Schuld daran ist hauptsächlich der je nach Projektumfang teilweise sehr aufwändige Build-Prozess, den Eclipse nach jeder Änderung in den SASS-Dateien zu durchlaufen hat. Das Speichern einer SASS-Datei dauert in dieser Konstellation (zumindest für meine Begriffe) inakzeptabel lang, was ganz und gar nicht gut mit einem jahrelang antrainierten »Save early, save often« harmoniert ... (Eventuell sitzt das Problem ja auch vor dem Bildschirm und ich habe ganz grundlegend etwas falsch gemacht – dann nehme ich alles zurück und bitte um Hilfestellung!)

sass --watch

Nicht wirklich zufrieden mit der Ant-basierten Lösung habe ich weiter nach einer praktikablen Technik gesucht und mich mit dem wichtigsten Bordmittel beschäftigt, dass SASS von Haus aus mitbringt: Das plattformübergreifend verfügbare Kommandozeilenprogramm sass (bzw. sass.bat unter Windows), welches generell für die Kompilierung von SASS-Dateien verantwortlich ist, und insbesondere sein Argument --watch, mit dessen Hilfe sich einzelne SASS-Dateien oder ganze Verzeichnisse rekursiv auf Änderungen überwachen lassen.

Die Verwendung dieses Tools hat sich für mich auf Anhieb wesentlich einfacher präsentiert als die oben beschriebenen Eclipse-Lösung. Einzig: sass --watch muss von der Kommandozeile aus gestartet werden, startet als Dienst und muss durchgehend laufen, solange Dateien oder Verzeichnisse überwacht werden sollen – nicht wirklich bequem. Wünschenswert wäre ein Hintergrunddienst (»Daemon«), der ohne weiteres Zutun startet, still seine Arbeit verrichtet und zudem einfach zu konfigurieren ist (Verwalten von zu überwachenden Dateien und Verzeichnissen).

Der im Folgenden präsentierte Ansatz war schließlich recht nahe liegend und nutzt den Umstand, dass unser interner Entwicklungsserver, auf dem unsere Webprojekte liegen, unter Gentoo Linux läuft. Ich bin kein ausgesprochener Gentoo-Crack, und sicher bietet die vorgestellte Lösung Optimierungspotenzial (Anregungen herzlich willkommen!). Immerhin aber funktioniert sie zumindest für uns hervorragend und kann mit entsprechender Systemkenntnis bestimmt auch recht einfach auf andere Server bzw. Betriebssysteme übertragen werden.

Initscript für Gentoo Linux

Ziel war es also, die SASS-Datei- und -Verzeichnis-Überwachung

  • serverseitig – also nicht ausgehend von der Entwicklungsumgebung, sondern dort, wo die SASS-Dateien tatsächlich gespeichert wurden – und gleichzeitig
  • als konfigurierbaren Dienst

zu betreiben. Unter Gentoo werden Dienste über sog. Initscripts kontrolliert, die im Verzeichnis /etc/init.d liegen und sich über Konfigurationsdateien im Verzeichnis /etc/conf.d konfigurieren lassen.

Folgendes Initscript, abgelegt als /etc/init.d/sasswatch, startet die SASS-Datei- und -Verzeichnis-Überwachung als Hintergrunddienst:

#!/sbin/runscript
# Copyright 2013 Joschi Kuphal
depend() {
	need localmount
	after bootmisc
	use logger
}
start() {
	ebegin "Starting sasswatch"
	function trim {
		echo $1 | sed 's/^ *//g' | sed 's/ *$//g';
	}
	function watch {
		if [[ "$1" =~ .*:.* ]]; then
			sass="`echo \"$1\" | cut -d: -f1`";
			sass=$(trim "$sass");
			css="`echo \"$1\" | cut -d: -f2`";
			css=$(trim "$css");
			if [ "$sass" != "" -a "$css" != "" -a \( \( -d "$sass" -a -d "$css" \) -o \( -f "$sass" -a \( -f "$css" -o ! -e "$css" \) \) \) ]; then
				echo " $sass:$css";
			fi;
		fi;
	}
	sasscmd="`which sass`";
	sassopts="--unix-newline --style ${SASSWATCH_STYLE:-expanded}";
	sasswatch=;
	# Determine if the compass framework shoud be loaded
	if [ "${SASSWATCH_COMPASS:-1}" = "1" ]; then
		sassopts="${sassopts} --compass";
	fi;
	# Determine all files and directories that have to be observed
	for watchconfig in `find /etc/sasswatch.d -type f`; do
		while read watch; do sasswatch="${sasswatch}`watch \"$watch\"`"; done < $watchconfig
	done;
	if [ "$sasswatch" = "" ]; then
		eend "No files or directories configured for observation";
	else
		start-stop-daemon --start --background --make-pidfile \
			--pidfile /var/run/sasswatch.pid --exec ${sasscmd} \
			--stdout /var/log/sasswatch.log -- \
			${sassopts} --watch ${sasswatch}
		eend $?
	fi;
}
stop() {
	ebegin "Stopping sasswatch"
	start-stop-daemon --stop --quiet --pidfile /var/run/sasswatch.pid
	eend $?
}

Der Dienst kann in zweierlei Hinsicht konfiguriert werden: Einerseits steuert die folgende Konfiguration, abgelegt unter /etc/conf.d/sasswatch, die Einbindung der Compass-Bibliothek sowie das CSS-Ausgabeformat, dass beim Kompilieren erzeugt wird (die verfügbaren Formate sind in der SASS-Referenz nachzuschlagen).

# The commented variables in this file are the defaults that are used
# in the init-script.  You don't need to uncomment them except to
# customize them to different values.
# Options for sasswatch
# SASSWATCH_COMPASS="1"
# SASSWATCH_STYLE="expanded"

Darüber hinaus erwartet der Dienst im Verzeichnis /etc/sasswatch.d Konfigurationsdateien für die zu überwachenden SASS-Dateien und -Verzeichnisse. Es können hier beliebig viele Konfigurationsdateien abgelegt werden, etwa projektweise, wobei die Dateinamen für den sasswatch-Dienst unerheblich sind. Jede dieser Konfigurationsdateien kann ihrerseits eine beliebige Anzahl von Quell-Ziel-Paaren definieren (eine Angabe je Zeile), wobei sowohl Dateien, als auch Verzeichnisse angegeben werden können. Quelle und Ziel müssen stets vom selben Typ sein und werden durch einen Doppelpunkt getrennt. Beispiel:

/pfad/zum/projekt/sass:/pfad/zum/projekt/css
/anderes/projekt/in.scss:/anderes/projekt/out.css

Der sasswatch-Dienst kann über die üblichen Kommandozeilenbefehle kontrolliert werden:

/etc/init.d/sasswatch start
/etc/init.d/sasswatch stop
/etc/init.d/sasswatch restart

Nach einer Änderung der zu überwachenden Dateien und Verzeichnisse muss der sasswatch-Dienst per restart neu initialisiert werden. Um den Dienst direkt bei Serverstart zu aktivieren, genügt die Aufnahme in den Standard-Runlevel:

rc-update add sasswatch default

Die Ausgabe, die das sass --watch-Kommando üblicherweise produzieren würde, wird im Dienstmodus in die Datei /var/log/sasswatch.log geschrieben. Auf Dauer macht es ggf. Sinn, eine entsprechende logrotate-Regel einzurichten, um die Logdatei nicht ins Unendliche wachsen zu lassen, doch eine Erläuterung hierzu würde das Thema dieses Artikels sprengen.

Der sasswatch-Dienst arbeitet im Stillen und konvertiert veränderte SASS-Dateien nahezu in Echtzeit. Für den Entwickler entsteht im Arbeitsprozess keine Verzögerung beim Speichern, und auch anderweitig muss er keine besonderen Vorkehrungen treffen oder Aktionen auslösen – seine SASS-Dateien werden quasi wie von »Zauberhand« zu CSS kompiliert.

Das sasswatch-Initscript samt Konfigurationsdatei kann zusammen mit einer beispielhaften Überwachungskonfiguration

hier heruntergeladen

werden. Bitte entpacken Sie das Archiv direkt auf der Rootebene / Ihres Gentoo-Servers.

Voraussetzungen unter Gentoo

Der Vollständigkeit halber seien an dieser Stelle noch die Softwarevoraussetzungen angeführt, die zur Nutzung des sasswatch-Dienstes unter Gentoo gegeben sein müssen. Führen Sie je nach Bedarf die folgenden Kommandos aus. Ggf. bietet es sich an, zuvor die gewünschte Ruby-Version in der Datei /etc/make.conf anzugeben, etwa durch RUBY_TARGETS="ruby19". Die letzte der folgenden Zeilen wird nur unter einer »hardened«-Variante des Betriebssystems benötigt:

emerge ruby
gem install sass compass listen
gem install --version '~> 0.8.8' rb-inotify
paxctl -m /usr/bin/ruby

Im Anschluss an Ruby können SASS – und bei Bedarf Compass – installiert werden. Für SASS selbst stehen Portage-ebuilds zur Verfügung, deren Verwendung insofern zu empfehlen ist, als dass die SASS-Installation dann von den üblichen Portage-Aktualisierungen profitiert. Compass muss zum gegenwärtigen Zeitpunkt in jedem Fall als Ruby-Gem installiert werden:

emerge sass
gem install compass

Alternativ kann auch SASS inklusive aller Zusatzkomponenten als Ruby-Gem installiert werden:

gem install sass compass listen
gem install --version '~> 0.8.8' rb-inotify