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.jsonkannst du unminified Dateien unterfiles-devdeklarieren und in Prod automatisch auffiles(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
- GitHub: https://github.com/jbsnewmedia/asset-composer-bundle
- Composer:
composer require jbsnewmedia/asset-composer-bundle