Composer, npm und Vendor sauber behandeln
Cache beschleunigt Builds durch Wiederverwendung von Downloadergebnissen. Artefakte übertragen gebaute Resultate zwischen Jobs. Wer beide verwechselt, kämpft mit inkonsistenten Builds, unnötig langen Pipeline-Laufzeiten und schwer reproduzierbaren Deployment-Artefakten für Magento.
Inhaltsverzeichnis
- 1. Der Grundunterschied zwischen Cache und Artefakten
- 2. Composer-Download-Cache richtig konfigurieren
- 3. Vendor-Ordner als Artefakt zwischen Jobs übertragen
- 4. npm und Tailwind: Cache vs. node_modules als Artefakt
- 5. generated/ und pub/static/ als Build-Artefakte
- 6. Cache-Keys: Reproduzierbarkeit durch Lock-File-Hashing
- 7. Vergleich: Was in Cache, was in Artefakte
- 8. Fallstricke bei Cache und Artefakten in Magento-Pipelines
- 9. Build-Zeit-Optimierung durch gezielten Cache-Einsatz
- 10. Zusammenfassung
- 11. FAQ
1. Der Grundunterschied zwischen Cache und Artefakten
Der konzeptionelle Unterschied zwischen GitLab Cache und Artefakten wird in vielen Pipelines falsch verstanden oder ignoriert – mit messbaren Konsequenzen für Build-Zeiten und Reproduzierbarkeit. Cache ist ein persistenter Speicher zwischen Pipeline-Läufen, der Daten speichert, die aufwendig zu beschaffen, aber nicht kritisch für die Korrektheit des Builds sind. Composer-Pakete, die einmal von Packagist heruntergeladen wurden, müssen beim nächsten Build nicht erneut heruntergeladen werden – sie können aus dem Cache gelesen werden, was die Netzwerklatenz eliminiert und die Build-Zeit reduziert.
Artefakte hingegen sind Dateien, die ein Job als Ergebnis seiner Arbeit produziert und die von nachfolgenden Jobs in derselben Pipeline konsumiert werden. Wenn der Build-Job vendor/ durch composer install befüllt, muss dieser befüllte Ordner als Artefakt an den Test-Job und den Deploy-Job übergeben werden. Ein Cache wäre hier falsch, weil der Cache aus einem früheren Build stammt und möglicherweise nicht zu der aktuellen composer.lock-Version passt.
Die wichtigste Regel: Was deterministisch aus dem Quellcode gebaut werden kann, gehört in ein Artefakt. Was nur die Beschaffungszeit verkürzt, aber das Ergebnis nicht beeinflusst, gehört in den Cache. Ein Vendor-Ordner ohne passende Lock-Datei ist ein Sicherheitsproblem und ein Reproduzierbarkeitsproblem. Ein Composer-Download-Cache ohne gültigen Vendor-Ordner ist nur ein leerer Zwischenspeicher – harmlos und nützlich.
2. Composer-Download-Cache richtig konfigurieren
Composer hat zwei verschiedene Caches: den Download-Cache, der heruntergeladene Pakete als ZIP-Archive speichert, und den Repository-Cache, der Packagist-Metadaten zwischenspeichert. Für GitLab-Pipelines ist der Download-Cache am wertvollsten, weil er verhindert, dass bei jedem Build dieselben Pakete erneut heruntergeladen werden. Typischerweise liegt dieser Cache unter ~/.composer/cache oder einem konfigurierten Verzeichnis.
Das korrekte Muster ist, das Composer-Cache-Verzeichnis als GitLab-Cache mit einem key zu konfigurieren, der auf dem Branch-Namen oder dem Hash der composer.lock basiert. Wenn sich die Lock-Datei ändert, wird ein neuer Cache-Key verwendet, und Composer lädt die neuen Pakete herunter – die alten Pakete bleiben für frühere Builds verfügbar. Nach dem Download durch composer install wird das fertige vendor/-Verzeichnis als Artefakt deklariert, damit nachfolgende Jobs es nutzen können, ohne Composer erneut auszuführen.
# build.yml — Composer cache and artifact configuration
build:composer:
stage: build
image: php:8.4-cli
variables:
COMPOSER_CACHE_DIR: "${CI_PROJECT_DIR}/.cache/composer"
COMPOSER_HOME: "${CI_PROJECT_DIR}/.cache/composer"
cache:
key:
files:
- composer.lock # Cache invalidates when lock file changes
paths:
- .cache/composer/ # Cache the downloaded ZIPs, not vendor/
policy: pull-push # Download existing cache, push updated cache
script:
- composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
artifacts:
paths:
- vendor/ # Built result passed to subsequent jobs
expire_in: 2 hours # Short TTL: artifacts are only needed within pipeline
only:
- main
- tags
- merge_requests
Ein wichtiges Detail ist die expire_in-Einstellung für Artefakte. Vendor-Ordner sind typischerweise sehr groß (Magento kann 400–600 MB erreichen) und werden nur innerhalb einer Pipeline benötigt. Eine Aufbewahrungszeit von zwei Stunden ist ausreichend, spart aber erheblich Speicherplatz auf dem GitLab-Server im Vergleich zu einem Standardwert von 30 Tagen oder ohne Limit.
3. Vendor-Ordner als Artefakt zwischen Jobs übertragen
In einer mehrstufigen Magento-Pipeline werden Composer-Abhängigkeiten im Build-Job installiert und danach in Test-Jobs, dem DI-Compile-Job und dem Deploy-Job benötigt. Die korrekte Methode, den befüllten Vendor-Ordner weiterzugeben, ist das Artefakt-System von GitLab. Jobs, die den Vendor-Ordner benötigen, deklarieren ihn als Abhängigkeit über needs oder erhalten ihn automatisch, wenn sie von einem Job abhängen, der Artefakte produziert.
Ein Fehler, der häufig in Pipelines auftaucht, ist das erneute Ausführen von composer install in jedem Job, der Vendor benötigt. Das verdoppelt oder verdreifacht die Laufzeit, weil jeder Job dasselbe Ergebnis berechnet, das schon vorhanden wäre, wenn Artefakte korrekt konfiguriert sind. Die Regel lautet: composer install läuft einmal im Build-Job, das Ergebnis wird als Artefakt für alle nachfolgenden Jobs gespeichert.
Der Vendor-Ordner eines Magento-Projekts ist groß, aber GitLab komprimiert Artefakte vor dem Hochladen und entpackt sie vor der Nutzung. In der Praxis sind 400 MB Vendor-Ordner als Artefakt deutlich schneller verfügbar als ein erneutes composer install aus dem Netzwerk, selbst wenn der Download-Cache vorhanden ist. Die Artefakt-Übertragung innerhalb des GitLab-Systems ist erheblich schneller als ein externes Paket-Download.
4. npm und Tailwind: Cache vs. node_modules als Artefakt
Für das Frontend-Build mit npm und Tailwind CSS gilt dasselbe Prinzip wie bei Composer. Der npm-Download-Cache – standardmäßig unter ~/.npm oder einem konfigurierten Verzeichnis – speichert heruntergeladene Pakete als Tarballs. Dieser Cache gehört in die GitLab-Cache-Konfiguration mit einem Key, der auf package-lock.json basiert. Das gebaute node_modules/-Verzeichnis und das CSS-Build-Ergebnis unter pub/static/ oder dem Tailwind-Output-Verzeichnis sind Artefakte.
Eine häufige Optimierung für npm-lastige Pipelines ist npm ci statt npm install. npm ci installiert exakt die Versionen aus der Lock-Datei, löscht immer zuerst das bestehende node_modules/ und ist typischerweise schneller als npm install in CI-Umgebungen. In Verbindung mit einem npm-Cache, der die heruntergeladenen Tarballs vorhält, ist npm ci die beste Kombination für Reproduzierbarkeit und Geschwindigkeit.
# build.yml — npm cache and Tailwind build artifact
build:frontend:
stage: build
image: node:22-alpine
variables:
NPM_CONFIG_CACHE: "${CI_PROJECT_DIR}/.cache/npm"
cache:
key:
files:
- package-lock.json # Cache invalidates on lock file change
paths:
- .cache/npm/ # Cache downloaded npm tarballs
policy: pull-push
script:
# npm ci: deterministic install from lock file
- npm ci --prefix app/design/frontend/Mironsoft/default/web/tailwind
# Build Tailwind CSS output
- npm run build --prefix app/design/frontend/Mironsoft/default/web/tailwind
artifacts:
paths:
# Pass built CSS to deploy job — not node_modules
- app/design/frontend/Mironsoft/default/web/tailwind/css/
- pub/static/frontend/
expire_in: 2 hours
needs:
- job: build:composer # Requires vendor/ artifact first
5. generated/ und pub/static/ als Build-Artefakte
In Magento entstehen durch setup:di:compile und setup:static-content:deploy zwei weitere Verzeichnisse, die Build-Artefakte sind: generated/ enthält den generierten DI-Code (Interceptors, Factories, Proxies), und pub/static/ enthält alle statischen Dateien für das Frontend. Diese Verzeichnisse werden im Build-Job erzeugt und müssen als Artefakte an den Deploy-Job übergeben werden.
Häufig wird setup:static-content:deploy als Server-seitiger Schritt nach dem Deployment ausgeführt. Das hat Nachteile: Es verlängert die Downtime während des Deployments, belastet den Produktionsserver mit dem Build-Prozess und macht das Deployment weniger reproduzierbar, weil das Build-Ergebnis von der Umgebung des Produktionsservers abhängt. Besser ist es, Static Content im Build-Job der Pipeline zu erstellen und das Ergebnis als Artefakt zu deployen.
6. Cache-Keys: Reproduzierbarkeit durch Lock-File-Hashing
Cache-Keys bestimmen, ob ein vorhandener Cache für einen bestimmten Build genutzt werden kann. Der einfachste Key ist ein Branch-Name, aber das bedeutet, dass derselbe Cache für alle Commits auf einem Branch gilt – auch wenn sich Abhängigkeiten geändert haben. Ein besserer Ansatz ist das Hashen der Lock-Datei in den Cache-Key. GitLab unterstützt dafür die key.files-Konfiguration, die automatisch einen SHA-basierten Key aus dem Inhalt der genannten Dateien berechnet.
Wenn composer.lock sich ändert, ändert sich der Cache-Key, und GitLab verwendet entweder einen vorhandenen Cache mit demselben Key (bei unveränderter Lock-Datei auf einem anderen Branch) oder erstellt einen neuen leeren Cache. Das alte Cache-Objekt bleibt für den alten Key verfügbar. Mit dieser Konfiguration ist sichergestellt, dass Composer nie mit einem veralteten Cache-Stand arbeitet, der zu einem anderen Lock-File gehört.
# Cache key strategy for Magento projects
# Combines branch name with lock file hash for isolation + reuse
.composer_cache: &composer_cache
cache:
key:
prefix: "composer-v1"
files:
- composer.lock
paths:
- .cache/composer/
policy: pull-push
.npm_cache: &npm_cache
cache:
key:
prefix: "npm-v1"
files:
- app/design/frontend/Mironsoft/default/web/tailwind/package-lock.json
paths:
- .cache/npm/
policy: pull-push
# Job using both caches
build:all:
stage: build
<<: *composer_cache
# Note: only one cache block per job; combine manually or use extends
script:
- composer install --no-dev --prefer-dist --optimize-autoloader
- npm ci --prefix app/design/frontend/Mironsoft/default/web/tailwind
- bin/magento setup:di:compile
- bin/magento setup:static-content:deploy de_DE -f
7. Vergleich: Was in Cache, was in Artefakte
Die folgende Tabelle zeigt die korrekte Zuordnung der wichtigsten Magento-Build-Bestandteile zu Cache und Artefakten. Diese Entscheidungen haben direkte Auswirkungen auf Build-Zeit, Speicherverbrauch und Reproduzierbarkeit der Pipeline.
| Verzeichnis / Datei | Cache | Artefakt | Begründung |
|---|---|---|---|
| .cache/composer/ | Ja | Nein | Heruntergeladene ZIP-Archive, kein Build-Ergebnis |
| vendor/ | Nein | Ja | Buildresultat, muss zu composer.lock passen |
| .cache/npm/ | Ja | Nein | Heruntergeladene npm-Tarballs |
| generated/ | Nein | Ja | DI-generierter Code, release-spezifisch |
| pub/static/ | Nein | Ja | Deploybare statische Assets |
Die Tabelle macht deutlich: Caches beschleunigen den Beschaffungsschritt, Artefakte transportieren das Ergebnis. Ein Vendor-Ordner im Cache würde bedeuten, dass unterschiedliche Builds auf demselben Branch denselben Vendor-Stand nutzen – unabhängig davon, ob die composer.lock geändert wurde. Das ist ein Reproduzierbarkeits- und Sicherheitsproblem. Als Artefakt mit Lock-File-basiertem Key wird sichergestellt, dass jeder Build exakt die Abhängigkeiten enthält, die die aktuelle Lock-Datei vorschreibt.
8. Fallstricke bei Cache und Artefakten in Magento-Pipelines
Der häufigste Fallstrick ist ein Cache, der nicht invalidiert wird, wenn sich Abhängigkeiten ändern. Teams, die den Cache-Key auf den Branch-Namen setzen, erleben sporadische Build-Fehler, wenn ein Entwickler Pakete hinzufügt und der nächste Build einen veralteten Cache findet. Die Lösung ist immer ein Lock-File-basierter Cache-Key. Der zweite häufige Fallstrick ist ein vergessenes cache: policy: pull in Jobs, die den Cache nur lesen und nicht aktualisieren sollen. Standardmäßig lädt jeder Job den Cache herunter und pusht ihn danach zurück – auch wenn sich nichts geändert hat. policy: pull reduziert unnötige Cache-Schreibvorgänge.
Ein dritter Fallstrick betrifft die Größe von Artefakten. Wenn node_modules/ als Artefakt konfiguriert wird (statt nur das Build-Ergebnis), können Artefakte mehrere Gigabyte groß werden. Das verlangsamt jeden Job, der diese Artefakte herunterladen muss, und erhöht den Speicherverbrauch auf dem GitLab-Server erheblich. Die Regel lautet: Als Artefakt nur das minimale Set übergeben, das nachfolgende Jobs wirklich benötigen. Für Tailwind-Builds ist das der CSS-Output, nicht der vollständige node_modules/-Ordner.
9. Build-Zeit-Optimierung durch gezielten Cache-Einsatz
Eine gut konfigurierte Cache-Strategie kann die Build-Zeit einer Magento-Pipeline von 15–20 Minuten auf 5–8 Minuten reduzieren. Der größte Gewinn entsteht durch das Cachen des Composer-Download-Caches: Ein typisches Magento-Projekt mit Hyvä-Theme lädt beim ersten Build 200–300 Pakete von Packagist herunter. Mit einem warmen Cache werden nur geänderte oder neue Pakete heruntergeladen, was die Netzwerkphase von 3–5 Minuten auf unter 30 Sekunden reduziert.
Für Teams, die parallel auf mehreren Branches arbeiten, ist die Cache-Isolierung durch Branch-spezifische Prefixe sinnvoll. Ein Feature-Branch kann so vom main-Branch-Cache profitieren (Fallback-Key), ohne diesen zu überschreiben. GitLab unterstützt Fallback-Keys durch die key-Konfiguration: Wenn kein Cache für den aktuellen Key gefunden wird, wird ein Fallback-Key versucht. Das ermöglicht es, den stabilen main-Branch-Cache als Warmup-Cache für neue Feature-Branches zu nutzen.
# Advanced cache strategy with fallback keys
build:composer:optimized:
stage: build
image: php:8.4-cli
variables:
COMPOSER_CACHE_DIR: "${CI_PROJECT_DIR}/.cache/composer"
cache:
# Primary key: exact lock file match
- key:
prefix: "composer-${CI_COMMIT_REF_SLUG}"
files:
- composer.lock
paths:
- .cache/composer/
policy: pull-push
# Fallback key: main branch cache as warmup
- key: "composer-main-fallback"
paths:
- .cache/composer/
policy: pull # Only read from fallback, never write to it
script:
- composer install --no-dev --prefer-dist --optimize-autoloader
artifacts:
paths:
- vendor/
expire_in: 3 hours
10. Zusammenfassung
Die korrekte Trennung von GitLab Cache und Artefakten für Composer, npm und den Vendor-Ordner ist eine der wichtigsten Optimierungen in Magento-CI-Pipelines. Cache beschleunigt den Beschaffungsschritt durch Wiederverwendung heruntergeladener Pakete. Artefakte transportieren gebaute Resultate zwischen Jobs innerhalb einer Pipeline. Vendor-Ordner und generierter Code gehören als Artefakte, nicht in den Cache, weil sie zu einer spezifischen Lock-Datei-Version gehören müssen.
Lock-File-basierte Cache-Keys stellen sicher, dass veraltete Caches nicht für neue Abhängigkeitsstände verwendet werden. Kurze Artefakt-TTLs sparen Speicherplatz, weil Build-Artefakte nur innerhalb einer Pipeline gebraucht werden. policy: pull für lesende Jobs verhindert unnötige Cache-Schreibvorgänge. Mit diesen Konfigurationen reduziert sich die Build-Zeit und die Reproduzierbarkeit der Pipeline steigt, weil jeder Build exakt auf dem steht, was die Lock-Dateien vorschreiben.
GitLab Cache vs. Artefakte — Das Wichtigste auf einen Blick
Cache verwenden für
.cache/composer/ und .cache/npm/ – heruntergeladene Pakete. Key: Hash der Lock-Datei. Beschleunigt Beschaffung, beeinflusst nicht Build-Korrektheit.
Artefakte verwenden für
vendor/, generated/, pub/static/ – gebaute Resultate. expire_in kurz halten. Zwischen Jobs innerhalb der Pipeline übertragen.
Lock-File-Keys
key.files: [composer.lock] und [package-lock.json] invalidieren den Cache automatisch bei Abhängigkeitsänderungen. Kein manueller Eingriff nötig.
Cache-Policy
Build-Jobs: pull-push. Test-Jobs und Deploy-Jobs: pull. Verhindert unnötige Cache-Schreibvorgänge und Konflikte zwischen parallelen Jobs.