in GitLab Pipelines integrieren
Hyvä Themes bringt Tailwind CSS v4 als CSS-first-Build in Magento. Wer diesen Build in die GitLab-Pipeline integriert, muss Node.js-Versionen, npm-Caching, Artefakt-Übergabe und die Reihenfolge gegenüber dem PHP-Build sauber koordinieren. Dieser Artikel zeigt, wie das in der Praxis funktioniert.
Inhaltsverzeichnis
- 1. Warum der Frontend-Build in die Pipeline gehört
- 2. Node.js-Version festlegen und reproduzieren
- 3. npm-Caching in GitLab CI korrekt konfigurieren
- 4. Tailwind CSS v4 im Pipeline-Job kompilieren
- 5. Build-Artefakt sauber übergeben
- 6. Static Content Deploy nach dem Frontend-Build
- 7. Typische Fehler beim Frontend-Build in CI
- 8. Frontend-Build-Strategien im Vergleich
- 9. Build-Zeit optimieren
- 10. Zusammenfassung
- 11. FAQ
1. Warum der Frontend-Build in die Pipeline gehört
Der häufigste Fehler bei Magento-Projekten mit Hyvä Themes ist ein Frontend-Build, der auf dem Entwickler-Laptop läuft und dessen Ergebnisse ins Repository committed werden. Das klingt pragmatisch, ist aber in der Praxis eine kontinuierliche Quelle von Inkonsistenzen: unterschiedliche Node.js-Versionen, unterschiedliche npm-Versionen, unterschiedliche Tailwind-Konfigurationen auf verschiedenen Entwickler-Maschinen führen zu CSS-Dateien, die je nach Umgebung leicht abweichen. Wer das Ergebnis committet, versioniert Artefakte statt Quellcode.
Die Alternative ist ein reproduzierbarer Build in der GitLab-Pipeline. Dort ist die Node.js-Version fixiert, npm ci stellt sicher, dass exakt die Versionen aus package-lock.json installiert werden, und das CSS-Build-Ergebnis ist ein deterministisches Artefakt des Pipeline-Runs. Das Ergebnis liegt dann nicht im Repository, sondern wird als Pipeline-Artefakt zwischen den Jobs übergeben und am Ende auf den Server deployed. Das ist sauberer, reproduzierbarer und schützt das Repository vor generiertem Code.
2. Node.js-Version festlegen und reproduzieren
Die Node.js-Version ist der häufigste Konfigurations-Drift zwischen Entwickler-Umgebung und CI. In Hyvä-Projekten mit Tailwind CSS v4 sollte Node.js 20 (LTS) verwendet werden. Die Version wird in der Datei .nvmrc im Repository festgelegt – ein einzeiliges File mit dem Inhalt 20. GitLab CI verwendet dann das Docker-Image node:20-alpine für den Frontend-Build-Job. So ist die Version sowohl lokal (via nvm) als auch in der Pipeline identisch.
Ein weiterer Stolperstein ist npm selbst. npm install und npm ci haben unterschiedliches Verhalten: npm install aktualisiert package-lock.json bei Bedarf, npm ci schlägt fehl wenn package.json und package-lock.json nicht übereinstimmen. In der CI-Pipeline gehört ausschließlich npm ci – das ist schneller, deterministisch und signalisiert sofort, wenn ein Entwickler package-lock.json vergessen hat zu committen. Das ist kein Komfort-Feature, sondern eine Reproduzierbarkeits-Garantie.
# .gitlab-ci.yml — Frontend build job for Hyvä / Tailwind CSS v4
build:frontend:
stage: build
image: node:20-alpine
variables:
# Cache npm modules across pipeline runs
NPM_CONFIG_CACHE: "$CI_PROJECT_DIR/.cache/npm"
THEME_PATH: "app/design/frontend/Mironsoft/default"
cache:
key:
files:
# Cache key changes when lock file changes
- "${THEME_PATH}/web/tailwind/package-lock.json"
paths:
- "${THEME_PATH}/web/tailwind/node_modules/"
- .cache/npm/
policy: pull-push
script:
# Install exact versions from lock file (no updates)
- npm ci
--prefix "${THEME_PATH}/web/tailwind"
--prefer-offline
# Build Tailwind CSS v4 (CSS-first approach)
- npm run build
--prefix "${THEME_PATH}/web/tailwind"
artifacts:
name: "frontend-${CI_COMMIT_SHORT_SHA}"
paths:
# Only the compiled CSS, not node_modules
- "${THEME_PATH}/web/css/"
expire_in: 1 day
when: on_success
3. npm-Caching in GitLab CI korrekt konfigurieren
Der größte Zeitfresser im Frontend-Build-Job ist das Herunterladen von npm-Paketen. Mit einem korrekt konfigurierten GitLab-Cache für node_modules fällt dieser Schritt bei unveränderten Abhängigkeiten komplett weg. Der Cache-Key muss auf package-lock.json zeigen: wenn sich die Lock-Datei ändert, wird ein neuer Cache erstellt. Wenn sie unverändert ist, wird der vorhandene Cache verwendet und npm ci mit --prefer-offline ausgeführt, was das lokale Cache-Verzeichnis bevorzugt.
Wichtig ist die Unterscheidung zwischen GitLab-Cache und GitLab-Artefakt. node_modules gehört in den Cache: es ist groß, wird zwischen Pipeline-Runs wiederverwendet und muss nicht versioniert werden. Das kompilierte CSS gehört in das Artefakt: es ist klein, wird zwischen Jobs innerhalb eines Pipeline-Runs weitergegeben und muss genau reproduzierbar sein. Wer node_modules als Artefakt definiert, lädt Hunderte Megabyte unnötig zwischen Jobs. Wer das kompilierte CSS nur im Cache hat, riskiert fehlende Artefakte beim nächsten Job.
4. Tailwind CSS v4 im Pipeline-Job kompilieren
Tailwind CSS v4 verwendet einen CSS-first-Ansatz: anstatt einer tailwind.config.js steuert eine theme.css-Datei die Konfiguration. Das Build-Kommando in Hyvä-Projekten lautet typischerweise npm run build, das intern Tailwind CLI mit dem konfigurierten Input-File aufruft. In der GitLab-Pipeline muss sichergestellt sein, dass das Input-File korrekt referenziert ist und dass der Output-Pfad mit dem erwarteten Artefakt-Pfad übereinstimmt.
Ein häufiges Problem: Tailwind v4 scannt standardmäßig alle Template-Dateien im Projekt nach verwendeten CSS-Klassen. In einer CI-Umgebung ist der Scan-Pfad wichtig: er muss die .phtml-Dateien des Hyvä-Themes erfassen, aber nicht den vendor/-Ordner durchsuchen, der Hunderte Megabyte an Dateien enthalten kann. Die Tailwind-Konfiguration in theme.css mit @source-Direktiven auf die relevanten Template-Verzeichnisse zu begrenzen, halbiert die Build-Zeit in vielen Projekten.
5. Build-Artefakt sauber übergeben
In einer mehrstufigen GitLab-Pipeline muss das Frontend-Build-Artefakt vom Build-Job an den Deploy-Job weitergegeben werden. Das geschieht über GitLab-Artefakte mit artifacts.paths. Der Build-Job definiert, welche Pfade als Artefakt gespeichert werden, und der Deploy-Job kann über needs auf diese Artefakte zugreifen. Wichtig: Artefakte werden automatisch zwischen Jobs in derselben Pipeline weitergegeben – auch wenn sie in unterschiedlichen Stages laufen.
Die kritische Entscheidung ist, welche Dateien Teil des Artefakts sein sollen. Für den Frontend-Build sind das: die kompilierte CSS-Datei unter web/css/styles.css und optionale Source-Maps für das Debugging. Nicht im Artefakt: node_modules/, das Build-Tool selbst, temporäre Dateien. Ein schlankes Artefakt beschleunigt den Upload und Download zwischen Jobs erheblich und reduziert den GitLab-Artefakt-Speicher. Eine typische kompilierte Tailwind-CSS-Datei ist 50–150 KB – das Artefakt sollte nie größer als wenige Megabyte sein.
6. Static Content Deploy nach dem Frontend-Build
In Magento mit Hyvä ist der Static Content Deploy (SCD) ein separater Schritt, der nach dem Frontend-Build läuft. SCD kompiliert Magento-Module-spezifische Assets, verarbeitet require-js-Bundles (in Hyvä minimal) und kopiert Theme-Assets in den pub/static/-Ordner. In der GitLab-Pipeline läuft SCD entweder als Teil des Build-Jobs (was Magento als Abhängigkeit erfordert) oder auf dem Zielserver als Teil des Deploy-Jobs.
Die sauberere Lösung für Hyvä-Projekte: SCD im Build-Job mit dem PHP-Image ausführen, nachdem der Frontend-Build das CSS produziert hat. Das Ergebnis – der komplette pub/static/-Ordner – wird als Artefakt weitergegeben und auf den Server deployed, ohne dass auf dem Server ein einzelner SCD-Befehl ausgeführt werden muss. Das ist schneller, reproduzierbarer und vermeidet das Problem, dass der Server während des SCD keine statischen Assets liefern kann.
# Combined PHP + Frontend build job
build:magento:
stage: build
image: php:8.4-cli
variables:
COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.cache/composer"
THEME_PATH: "app/design/frontend/Mironsoft/default"
cache:
key:
files:
- composer.lock
paths:
- .cache/composer/
policy: pull-push
before_script:
# Install Node.js 20 into PHP image
- curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
- apt-get install -y nodejs
# Install PHP extensions required by Magento
- docker-php-ext-install pdo_mysql bcmath intl
script:
# PHP dependencies
- composer install
--no-dev --prefer-dist --no-interaction --optimize-autoloader
# Frontend build (npm ci + Tailwind)
- npm ci --prefix "${THEME_PATH}/web/tailwind" --prefer-offline
- npm run build --prefix "${THEME_PATH}/web/tailwind"
# Magento DI compile
- php bin/magento setup:di:compile
# Static content deploy for all locales
- php bin/magento setup:static-content:deploy
de_DE en_US
-t Mironsoft/default --force
artifacts:
name: "magento-build-${CI_COMMIT_SHORT_SHA}"
paths:
- vendor/
- generated/
- pub/static/
expire_in: 2 hours
7. Typische Fehler beim Frontend-Build in CI
Der häufigste Fehler ist eine fehlende oder veraltete package-lock.json. Wenn npm ci in der Pipeline fehlschlägt, liegt es fast immer daran, dass die Lock-Datei nicht dem aktuellen Stand von package.json entspricht. Die Lösung: lokal npm install ausführen, die aktualisierte Lock-Datei committen und die Pipeline neu starten. npm ci darf niemals still die Lock-Datei aktualisieren – das ist sein Designprinzip und schützt vor unbeabsichtigten Dependency-Updates in der CI.
Ein zweiter typischer Fehler ist das Fehlen von CSS-Klassen im kompilierten Output. Wenn Tailwind Template-Dateien nicht findet, generiert es nur die Base-Styles. Die Lösung: in der theme.css explizite @source-Pfade auf die Template-Verzeichnisse setzen. In Hyvä-Projekten sind das typischerweise die .phtml-Dateien im Theme-Verzeichnis und die Alpine.js-Komponenten. Ein dritter Fehler: den Build außerhalb des Theme-Verzeichnisses ausführen, sodass relative Pfade in der Tailwind-Konfiguration nicht aufgelöst werden können.
8. Frontend-Build-Strategien im Vergleich
Es gibt verschiedene Ansätze, den Frontend-Build in Magento-Projekten zu handhaben. Die Wahl hat erhebliche Auswirkungen auf Reproduzierbarkeit, Pipeline-Geschwindigkeit und Team-Komfort.
| Strategie | Reproduzierbar | Pipeline-Geschwindigkeit | Empfehlung |
|---|---|---|---|
| CSS lokal gebaut, ins Repo committed | Nein | Schnell (kein Build) | Nicht empfohlen |
| Build auf dem Server beim Deploy | Bedingt | Langsam (kein Cache) | Nicht empfohlen |
| Build in GitLab CI, Artefakt | Ja | Schnell mit Cache | Empfohlen |
| Build in separatem Job, dann combiniert | Ja | Parallelisierbar | Empfohlen für große Projekte |
| Docker-Image mit pre-built Assets | Ja | Sehr schnell | Für Container-Deployments |
9. Build-Zeit optimieren
Wenn der Frontend-Build-Job mehr als zwei Minuten dauert, gibt es mehrere Optimierungsansätze. Der wirksamste ist das korrekte npm-Caching: wenn node_modules aus dem Cache geladen wird, entfällt das Herunterladen komplett. Der zweite Ansatz ist die Einschränkung des Tailwind-Scan-Bereichs: mit expliziten @source-Pfaden auf die relevanten Template-Verzeichnisse scannt Tailwind nur wenige Hundert Dateien statt des gesamten Projekts.
Ein dritter Hebel ist die parallele Ausführung von PHP- und Frontend-Build. Wenn beide als separate Jobs in derselben Stage laufen, können sie auf verschiedenen Runnern gleichzeitig ausgeführt werden. Ein kombinierten Build-Job, der erst PHP-Abhängigkeiten installiert und dann den Frontend-Build ausführt, ist einfacher zu konfigurieren, aber langsamer als zwei parallele Jobs. Für Projekte mit langen Build-Zeiten lohnt sich die Auftrennung: der Deploy-Job wartet dann auf beide über needs: ["build:php", "build:frontend"].
10. Zusammenfassung
Der Frontend-Build mit npm und Tailwind CSS v4 gehört in die GitLab-Pipeline, nicht auf den Entwickler-Laptop oder den Produktionsserver. Die Kombination aus fixierter Node.js-Version, npm ci für deterministischen Dependency-Install, GitLab-Cache für node_modules und schlankem Artefakt für das kompilierte CSS ist der reproduzierbare Standard für Hyvä-Magento-Projekte. Diese Struktur garantiert, dass jeder Deployment auf jedem Server denselben CSS-Stand hat – unabhängig davon, wer den Build ausgelöst hat.
Die Integration des Static Content Deploy in denselben Build-Job bringt den vollständigen pub/static/-Ordner als Artefakt in die Pipeline, sodass der Zielserver keinen einzigen Build-Schritt mehr ausführen muss. Das macht Deployments schneller, reduziert die Serverlast während des Deployments und eliminiert eine ganze Klasse von Fehlern, die nur in Produktion auftreten, weil dort eine andere Node.js-Version installiert ist als auf dem Entwickler-Laptop.
Frontend-Builds in GitLab CI — Das Wichtigste auf einen Blick
Node.js-Version
.nvmrc + Docker-Image node:20-alpine in der Pipeline – identisch mit lokaler Entwicklungsumgebung.
npm ci statt npm install
Deterministischer Install aus package-lock.json, schlägt sofort fehl bei Abweichungen – Pflicht in CI.
Cache vs. Artefakt
node_modules in den Cache, kompiliertes CSS als Artefakt – nie umgekehrt.
Tailwind-Scan begrenzen
@source-Pfade in theme.css auf Template-Verzeichnisse begrenzen – halbiert die Build-Zeit in großen Projekten.