NPM-Paket für mehrere Dateien ausführen (am Beispiel von csso-cli)

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:

  1. 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.
  2. 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 🙂 )!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert