Einige NPM-Pakete bieten bereits direkt die Möglichkeit, sich auf mehrere Dateien eines Verzeichnisses gleichzeitig anwenden zu lassen – so kann node-sass beispielsweise ein ganzes Verzeichnis von SCSS-Dateien in CSS-Dateien umwandeln. Das Minifier-Tool csso-cli bietet eine Option für mehrere Dateien als Input von Haus aus nicht an – hier zeige ich einen Workaround, um das trotzdem umzusetzen.
Die Ausgangslage und das Problem
Zunächst der Grund, warum ich so was brauche. Seit Kurzem versuche ich NPM-Skripte statt Gulp für den Build-Prozess zu verwenden. Für ein WordPress-Theme erstelle ich die Haupt-CSS-Datei aus mehreren SCSS-Dateien und erzeuge anschließend noch eine RTL-Version der Styles. Danach soll von beiden Dateien eine minifizierte Version erstellt werden. Es gibt Minifizierungs-Tools, die ein Verzeichnis als Basis nutzen können (zum Beispiel Minifier) – ich möchte allerdings csso-cli nutzen, um die Source-Maps zu den SCSS-Dateien mitnehmen zu können.
Nun könnte ich natürlich für diese zwei Dateien jeweils einen einzelnen csso-cli-Aufruf ausführen, hätte dabei aber verschiedene Probleme:
- Es heißt ja immer so schön Don’t repeat yourself, und das würde ich bei je einem Aufruf pro Datei für die eigentlich gleiche Aufgabe nicht wirklich einhalten.
- Wenn eine weitere CSS-Datei hinzukommt, die minifiziert werden soll, muss ich das Build-Skript anpassen.
Das wäre also nicht gerade eine optimale Lösung, weshalb ich nach einem Weg gesucht habe, csso-cli (beziehungsweise letztlich jedes NPM-Paket und andere Befehle) automatisch für mehrere Dateien auszuführen.
Meine Lösung
Die Lösung, die dabei herausgekommen ist, basiert auf dem find
-Befehl von Linux. Ich bin der Lösung über verschiedene Sites näher gekommen – die entscheidende Antwort habe ich dann auf askubuntu.com gefunden. Und so sieht die Lösung aus (abzüglich einiger csso-cli-Optionen, die hier nicht relevant sind):
find assets/css/ -iname '*.css' -and -not -iname '*.min.css' -exec sh -c 'node_modules/csso-cli/bin/csso {} --output ${0%.css}.min.css' {} \;
Code-Sprache: Bash (bash)
Wir suchen in assets/css
alle Dateien, die auf .css
enden und möchten davon die Dateien mit .min.css
am Ende ausschließen. Danach führen wir für jede der gefundenen Dateien ein Shell-Skript aus, und zwar das csso-cli. Über {}
bekommen wir den Dateinamen mit Pfad der aktuellen CSS-Datei – genau das, was csso-cli als ersten Parameter erwartet. Für den --output
-Parameter geben wir über ${0%.css}
den Pfad und Dateinamen ohne Endung an und hängen .min.css
dahinter (über ${0}
haben wir Zugriff auf {}
, den ersten positional parameter des Shell-Skripts, das wieder den Pfad und Dateinamen enthält). Das Ende des Skripts wird nach dem positional parameter mit \;
gekennzeichnet.
Wenn wir diese Zeile nun genau so nehmen und als Node-Skript nutzen möchten, bekommen wir den folgenden Fehler:
npm ERR! Failed to parse json
npm ERR! Unexpected token ';'
Code-Sprache: Bash (bash)
Zur Behebung des Problems passen wir das Ende an, sodass dort \\;
steht. So sieht das Ergebnis im "scripts":
-Teil meiner package.json
aus (jetzt auch komplett mit allen Optionen, die ich nutze):
"minify-css": "find assets/css/ -iname '*.css' -and -not -iname '*.min.css' -exec sh -c 'node_modules/csso-cli/bin/csso {} --input-map auto --map inline --output ${0%.css}.min.css' {} \\;"
Code-Sprache: Bash (bash)
Über npm run minify-css
kann ich nun alle CSS-Dateien im assets/css
-Verzeichnis minifizieren, die noch nicht minifiziert sind. Über Abwandlung des Skripts lässt sich das natürlich auch für andere NPM-Pakete nutzen.
Wenn ihr Vorschläge habt, wie sich das verbessern lässt, schreibt gerne einen Kommentar (natürlich auch, wenn ihr was anderes dazu sagen wollt 🙂 )!