Zur Übersicht
Jürgen Schwind 8 Dec 2025 Symfony, PHP, Composer, Assets, Frontend, Twig, Cache-Busting
Symfony AssetComposerBundle: Assets direkt aus dem vendor/ laden – schnell, simpel, immer aktuell

Symfony AssetComposerBundle: Assets direkt aus dem vendor/ laden – schnell, simpel, immer aktuell

Warum noch ein Asset‑Bundle?

Wer schon einmal ein Projekt mit ein paar externen CSS/JS‑Bibliotheken gepflegt hat, kennt die Reibungspunkte: Dateien kopieren, Pfade pflegen, Versionen aktualisieren, Cache leeren. Das kostet Zeit – und ist fehleranfällig. Genau hier setzt das AssetComposerBundle an: Es holt deine Assets direkt aus dem vendor‑Verzeichnis, verwaltet sie zentral, und versieht sie automatisch mit einer Versionsnummer auf Basis des Datei‑Zeitstempels. Ergebnis: Weniger Overhead, weniger Drift, immer aktuelle Assets.

Die Idee in einem Satz

„Composer‑native“ Asset‑Verwaltung: Du installierst Bibliotheken als Composer‑Pakete und bindest ihre Dateien ohne Kopierschritt direkt in Twig ein – inklusive Cache‑Busting über den mtime der Datei.

Highlights

  • Verwalte CSS/JS direkt aus Composer‑Paketen (ohne Kopieren in public/)
  • Automatisches Versioning per Dateizeitstempel für sauberes Cache‑Busting
  • Elegante Twig‑Integration (addAssetComposer, renderAssetComposerStylesheets, renderAssetComposerJavascripts)
  • Optionale Auswahl, welche Dateien exportiert werden (inkl. dev‑only) via assetcomposer.json
  • Funktioniert in Symfony 6.4 und 7.0

Installation

composer require jbsnewmedia/asset-composer-bundle

Das Bundle registriert sich automatisch (Flex). Anforderungen: PHP ≥ 8.1, Symfony 6.4/7.0.

Quickstart: Assets hinzufügen und rendern

1) Bibliotheken installieren (Beispiel):

composer require twbs/bootstrap
composer require components/font-awesome
composer require avalynx/avalynx-alert

2) In beliebigen Twig‑Templates Assets vormerken:

{% do addAssetComposer('twbs/bootstrap/dist/css/bootstrap.css') %}
{% do addAssetComposer('components/font-awesome/css/all.css') %}
{% do addAssetComposer('avalynx/avalynx-alert/dist/css/avalynx-alert.css') %}
{% do addAssetComposer('avalynx/avalynx-alert/dist/js/avalynx-alert.js') %}

3) Im Layout ausgeben:

<!DOCTYPE html>
<html>
<head>
    {% block stylesheets %}
        {{ renderAssetComposerStylesheets() }}
    {% endblock %}
</head>
<body>
    {% block body %}{% endblock %}
    
    {% block javascripts %}
        {{ renderAssetComposerJavascripts() }}
    {% endblock %}
    
    {{ renderAssetComposerJavascripts('bottom') }}
</body>
</html>

Das Bundle sorgt dafür, dass jeder Asset‑Pfad mit einem Query‑Parameter ?v=<mtime> versehen wird. Browser und Proxies erkennen Änderungen zuverlässig – ohne manuelle Versionierung.

Optional: assetcomposer.json

Pakete können (oder du in eigenen Paketen) eine assetcomposer.json mitgeben, die steuert, welche Dateien im Projekt sichtbar sein sollen – getrennt nach Production und Development:

{
  "name": "library-name",
  "files": [
    "dist/css/styles.css",
    "dist/js/scripts.js"
  ],
  "files-dev": [
    "src/css/dev-styles.css",
    "src/js/dev-scripts.js"
  ]
}

So bleibt der Output deterministisch, und du vermeidest, dass versehentlich „interne“ Dateien im Projekt landen.

Wie funktioniert das Cache‑Busting?

Statt auf Paketversionen oder Hash‑Pipelines setzt das Bundle auf den simplen und robusten Dateizeitstempel (mtime). Jede URL erhält ?v=<timestamp>. Ändert sich die Datei, ändert sich der Timestamp – und damit die URL. Vorteile:

  • Keine zusätzliche Build‑Stufe erforderlich
  • Funktioniert mit jeder Datei, unabhängig vom Paket
  • In Produktion genauso zuverlässig wie lokal

Wann ist das Bundle die richtige Wahl?

  • Du nutzt hauptsächlich Bibliotheken aus Composer (Bootstrap, Font Awesome, kleine JS‑Utilities) und willst sie ohne Kopier‑Workflows einbinden.
  • Du brauchst zuverlässiges Cache‑Busting, ohne eine komplette Asset‑Pipeline zu fahren.
  • Du möchtest dev‑only Assets (z. B. unminified Dateien) sauber trennen können.

Nicht ideal ist der Ansatz, wenn du ein komplexes Frontend‑Build (z. B. mit Vite/Webpack, TypeScript, Code‑Splitting) betreibst – hier ergänzt das Bundle ggf. nur externe Vendor‑Assets.

Praxis‑Tipps

  • Gruppierung: Nutze die Möglichkeit, JavaScripts auch „unten“ (renderAssetComposerJavascripts('bottom')) zu rendern, um den LCP zu verbessern.
  • Mischung mit eigenen Assets: Eigene Dateien kannst du wie gewohnt aus public/ einbinden; Vendor‑Assets kommen über das Bundle. So bleibt die Verantwortung klar getrennt.
  • Produktion vs. Entwicklung: In assetcomposer.json kannst du unminified Dateien unter files-dev deklarieren und in Prod automatisch auf files (minified) setzen.

Troubleshooting

  • „Datei wird nicht gefunden“: Stimmt der Pfad relativ zum Paket‑Root im vendor/? Beispiel: twbs/bootstrap/dist/css/bootstrap.css.
  • „Änderungen werden nicht geladen“: Prüfe, ob Browser‑Cache aktiv ist. Durch ?v=<mtime> sollten Änderungen allerdings sofort sichtbar sein.
  • „Ich brauche SRI‑Hashes“: Derzeit fokussiert das Bundle auf pragmatisches Laden aus vendor/. Für SRI kannst du bei Bedarf eine kleine Twig‑Erweiterung ergänzen oder einen Build‑Schritt nachrüsten.

Fazit

Das AssetComposerBundle ist eine kleine, aber wirkungsvolle Abkürzung für viele Symfony‑Projekte: Keine redundanten Kopierschritte, sauberes Cache‑Busting, klare Twig‑APIs. Wer seine Frontend‑Assets bewusst schlank hält und Composer als zentrale Bezugsquelle nutzt, spart damit jeden Tag ein bisschen Zeit – und vermeidet typische Fehler.

Links