Bundler war gestern
Webpack konfigurieren, npm-Pakete warten, Build-Pipelines debuggen — das kostet in Symfony-Projekten oft mehr Zeit als die eigentliche Frontendlogik. Symfony AssetMapper macht den Bundler für die meisten Projekte überflüssig: Import Maps, automatisches Versioning und ES-Module direkt aus PHP, ohne Node.js-Build-Schritt.
Inhaltsverzeichnis
- 1. Warum Symfony AssetMapper den Bundler ersetzt
- 2. Installation und Erstkonfiguration
- 3. Import Maps: Browser-natives Module-System
- 4. Vendor-Pakete ohne npm einbinden
- 5. Automatisches Versioning und Cache-Busting
- 6. Stimulus und Symfony UX ohne Build-Schritt
- 7. CSS mit AssetMapper verwalten
- 8. Migration von Webpack Encore zu AssetMapper
- 9. AssetMapper vs. Webpack Encore im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum Symfony AssetMapper den Bundler ersetzt
Der klassische Frontend-Workflow in Symfony-Projekten sah jahrelang so aus: Webpack Encore konfigurieren, npm install ausführen, Build-Fehler nach Node.js-Updates debuggen, separate Watcher-Prozesse neben dem PHP-Entwicklungsserver betreiben. Das alles, bevor auch nur ein JavaScript geschrieben wurde. Symfony AssetMapper, eingeführt in Symfony 6.3 und stabilisiert in 6.4, beseitigt diese gesamte Schicht: Es nutzt native Browser-Features — konkret Import Maps und ES-Module — die heute in allen modernen Browsern unterstützt werden, ohne dass ein Bundling-Schritt nötig wäre.
Der entscheidende technologische Wandel dahinter: Aktuelle Browser können ES-Module nativ auflösen. Das bedeutet, ein import { createApp } from 'vue' im Browser funktioniert ohne Bundler, sofern eine Import Map dem Browser sagt, unter welcher URL das Paket liegt. Symfony AssetMapper verwaltet genau diese Import Maps — es mappt Paketnamen auf versionierte URLs, sorgt für Cache-Busting durch Datei-Hashes und liefert Assets direkt aus dem assets/-Verzeichnis aus, ohne Kompilierungsschritt. Für Projekte ohne komplexe Build-Pipelines — und das sind in der Praxis die meisten traditionellen Symfony-Webanwendungen — ist das ein erheblicher Gewinn an Einfachheit.
2. Installation und Erstkonfiguration
Symfony AssetMapper ist seit Symfony 6.3 Bestandteil des Symfony-Kernpakets und benötigt keine externe Installation. In neuen Projekten, die mit symfony new --webapp erstellt werden, ist es standardmäßig aktiv. In bestehenden Projekten installiert man es über composer require symfony/asset-mapper symfony/asset. Der Symfony Flex Recipe legt automatisch die Verzeichnisstruktur an: assets/app.js als Einstiegspunkt, assets/styles/app.css für globale Stile und die importmap.php-Datei im Projektstamm, welche die Import-Map-Konfiguration enthält.
Die Konfiguration in config/packages/asset_mapper.yaml legt fest, welche Verzeichnisse Symfony AssetMapper als Asset-Quellen verwaltet. Standardmäßig ist das nur assets/, aber beliebig viele Pfade lassen sich hinzufügen — etwa wenn ein Bundle eigene Assets mitbringt oder Assets aus mehreren Modulen zusammengeführt werden sollen. In Templates bindet man Assets mit der Twig-Funktion asset() ein, die automatisch den versionierten Pfad mit Hash-Suffix erzeugt. Das Import-Map-Tag { { importmap('app') } } injiziert die vollständige Import-Map sowie den Einstiegspunkt in das HTML-Dokument — eine einzige Zeile ersetzt den kompletten script- und link-Block, den Webpack Encore früher generiert hat.
<?php
// importmap.php — managed by Symfony AssetMapper
// Do not edit manually; use: bin/console importmap:require <package>
return [
'app' => [
// Entry point: assets/app.js
'path' => 'app.js',
'entrypoint' => true,
],
'@hotwired/stimulus' => [
// Downloaded and versioned locally by AssetMapper
'version' => '3.2.2',
],
'@symfony/stimulus-bundle' => [
'path' => '@symfony/stimulus-bundle/loader.js',
],
'bootstrap' => [
'version' => '5.3.3',
],
'bootstrap/dist/css/bootstrap.min.css' => [
'version' => '5.3.3',
'type' => 'css',
],
];
3. Import Maps: Browser-natives Module-System
Import Maps sind ein Web-Standard (WHATWG), der im Browser nativ verfügbar ist. Sie erlauben es, bare Imports wie import { Controller } from '@hotwired/stimulus' auf konkrete URLs aufzulösen, ohne dass ein Bundler die Imports umschreibt. Das <script type="importmap">-Tag im HTML enthält ein JSON-Objekt, das Paketnamen auf URLs mapped. Symfony AssetMapper generiert dieses Tag automatisch aus der importmap.php-Konfiguration und löst dabei versionierte Asset-URLs auf — inklusive Content-Hash für zuverlässiges Cache-Busting.
Das Resultat im generierten HTML: Der Browser erhält eine Import Map mit allen bekannten Paketen und ihren URLs, gefolgt vom Einstiegspunkt-Skript. Alle Importe in assets/app.js und transitiven Modulen werden vom Browser direkt gegen die Import Map aufgelöst — kein Bundle, kein Webpack-Output, keine CommonJS-Wrapper. Symfony AssetMapper lädt Vendor-Pakete standardmäßig lokal herunter und liefert sie von der eigenen Domain aus, was CSP-Konfiguration erheblich vereinfacht und externe Abhängigkeiten zur Build-Zeit fixiert, statt sie zur Laufzeit von einem CDN zu laden.
{# templates/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
{# AssetMapper injects the full Import Map + entrypoint script #}
{ { importmap('app') } }
{# CSS assets — versioned automatically with content hash #}
<link rel="stylesheet" href="{ { asset('styles/app.css') } }">
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
{# Generated HTML output (simplified): #}
{#
<script type="importmap">
{
"imports": {
"app": "/assets/app-a1b2c3d4.js",
"@hotwired/stimulus": "/assets/vendor/@hotwired/stimulus-e5f6a7b8.js",
"bootstrap": "/assets/vendor/bootstrap-c9d0e1f2.js"
}
}
</script>
<script type="module">import 'app';</script>
#}
4. Vendor-Pakete ohne npm einbinden
Das Hinzufügen externer JavaScript-Pakete erfolgt mit Symfony AssetMapper über den Befehl bin/console importmap:require paketname. Der Befehl fügt das Paket zur importmap.php hinzu und lädt es von jsDelivr herunter in das assets/vendor/-Verzeichnis. Von dort wird es als normales Asset versioniert und ausgeliefert — ohne npm, ohne node_modules, ohne Package-Lock-Konflikte. Das Paket ist sofort im JavaScript über seinen Paketnamen importierbar, weil Symfony AssetMapper die Import Map aktualisiert.
Updates von Vendor-Paketen erfolgen mit bin/console importmap:update — es prüft alle eingetragenen Pakete auf neuere Versionen und aktualisiert importmap.php sowie die heruntergeladenen Dateien im assets/vendor/-Verzeichnis. Das assets/vendor/-Verzeichnis gehört nicht in die Versionsverwaltung, sondern wird in der .gitignore ausgeschlossen. Stattdessen committet man nur die importmap.php, und nach einem git clone stellt bin/console importmap:install alle Vendor-Dateien wieder her — analog zu composer install für PHP-Pakete.
5. Automatisches Versioning und Cache-Busting
Eines der zentralen Features von Symfony AssetMapper ist das automatische Versioning aller Assets. Jede Datei im überwachten assets/-Verzeichnis erhält beim Deployment einen Content-Hash als Teil des Dateinamens: app.js wird zu app-a1b2c3d4.js. Das ermöglicht aggressive Browser-Caching mit langen Cache-Control: max-age-Headern, weil sich der Dateiname bei jeder Änderung ändert und somit immer frische Inhalte laden. Twig-Templates nutzen die asset()-Funktion, die automatisch den versionierten Pfad auflöst — im Template steht asset('images/logo.svg'), im HTML-Output erscheint /assets/images/logo-f7e8d9c0.svg.
Im Entwicklungsmodus arbeitet Symfony AssetMapper ohne Hashes und liefert Assets direkt aus dem Dateisystem — jede Änderung ist sofort im Browser sichtbar, ohne Build-Schritt. Im Produktionsmodus erzeugt bin/console asset-map:compile alle versionierten Dateien im public/assets/-Verzeichnis. Dieser Schritt ersetzt den Webpack-Build im Deployment-Workflow und ist erheblich schneller: Keine Transpilierung, kein Tree-Shaking, kein Bundling — nur Datei-Kopieren mit Hash-Umbenennung. Das Ergebnis liegt sofort bereit und das public/assets/-Verzeichnis kann direkt von einem CDN oder Reverse Proxy gecached werden.
6. Stimulus und Symfony UX ohne Build-Schritt
Symfony AssetMapper ist vollständig in das Symfony UX-Ökosystem integriert. Stimulus-Controller, das JavaScript-Mikroframework hinter Symfony UX, laufen ohne Webpack: Nach composer require symfony/ux-stimulus-bundle und bin/console importmap:require @hotwired/stimulus ist Stimulus ohne npm-Schritt verfügbar. Symfony AssetMapper scannt das assets/controllers/-Verzeichnis automatisch nach Stimulus-Controllern und registriert sie, sodass data-controller="hello" im HTML sofort mit assets/controllers/hello_controller.js verbunden ist.
Symfony UX-Komponenten wie Turbo, Chart.js-Integration oder Cropperjs folgen demselben Muster: Das PHP-Paket wird über Composer installiert, Symfony Flex registriert die notwendigen JavaScript-Abhängigkeiten in der importmap.php, und nach bin/console importmap:install sind sie verwendbar. Das assets/controllers.json-Format aus der alten Webpack-Encore-Ära wird von Symfony AssetMapper ebenfalls unterstützt, was die Migration von bestehenden UX-Projekten vereinfacht. Der gesamte UX-Workflow — Stimulus-Controller schreiben, in Templates verwenden, im Browser sehen — funktioniert ohne einen einzigen npm-Befehl.
// assets/controllers/dropdown_controller.js
// Stimulus controller — no build step needed with Symfony AssetMapper
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
// Define target elements accessible via this.xTarget
static targets = ['menu', 'button'];
// Define values with type and default
static values = {
open: { type: Boolean, default: false },
};
connect() {
// Called when the controller connects to the DOM
this.updateMenu();
}
toggle() {
this.openValue = !this.openValue;
}
openValueChanged() {
this.updateMenu();
}
updateMenu() {
// Toggle ARIA and visibility based on state value
this.menuTarget.hidden = !this.openValue;
this.buttonTarget.setAttribute('aria-expanded', String(this.openValue));
}
}
7. CSS mit AssetMapper verwalten
CSS-Dateien verwaltet Symfony AssetMapper wie JavaScript-Assets: Jede Datei im assets/-Verzeichnis wird versioniert und per asset()-Funktion referenziert. Globale Stile liegen in assets/styles/app.css, komponentenspezifische CSS-Dateien in Unterordnern. CSS-Importe per @import werden von Symfony AssetMapper aufgelöst — allerdings ohne PostCSS-Transformationen, weil kein Build-Schritt läuft. Das bedeutet: Vanilla-CSS-Features wie Custom Properties, :is(), :has() und CSS-Nesting funktionieren dank moderner Browser direkt, während CSS-Präprozessoren wie Sass nicht ohne weiteres nutzbar sind.
Wer Tailwind CSS in einem Symfony AssetMapper-Projekt nutzen möchte, greift auf das Tailwind CLI-Binary zurück, das unabhängig von npm funktioniert: ./tailwindcss -i assets/styles/app.css -o public/assets/styles/app.min.css --watch überwacht Änderungen und baut die CSS-Datei ohne Node.js-Projekt neu. Im Deployment-Workflow läuft das Tailwind CLI als separater Build-Schritt, bevor asset-map:compile die restlichen Assets kompiliert. Diese Kombination ermöglicht Tailwind ohne das volle npm-Ökosystem: kein package.json, kein node_modules, nur das Standalone-Binary.
8. Migration von Webpack Encore zu AssetMapper
Die Migration eines bestehenden Symfony-Projekts von Webpack Encore zu Symfony AssetMapper ist in den meisten Fällen ein Wochenendsworkflow, kein Monats-Projekt. Der erste Schritt: composer require symfony/asset-mapper und bin/console importmap:require für alle JavaScript-Pakete, die bisher in package.json standen. Der zweite Schritt: JavaScript-Dateien von CommonJS-Syntax (require(), module.exports) auf ES-Module-Syntax (import, export) umstellen, da Symfony AssetMapper ausschließlich mit ES-Modulen arbeitet. Das ist in modernen Projekten meist trivial — in älteren Projekten mit vielen CommonJS-Abhängigkeiten kann dieser Schritt aufwändiger sein.
Kritischer Punkt bei der Migration: Pakete, die kein ES-Modul-Format anbieten und nur als CommonJS verfügbar sind, funktionieren nicht direkt mit Symfony AssetMapper. jsDelivr liefert für die meisten populären Pakete ESM-Varianten aus, aber es gibt Ausnahmen. Legacy-Pakete, die intern auf window-Globals angewiesen sind oder CommonJS-spezifische Features nutzen, müssen entweder durch ES-Modul-kompatible Alternativen ersetzt oder weiterhin über Webpack gebündelt werden. Für solche Ausnahmen ist ein Hybrid-Ansatz möglich: Webpack bündelt nur die problematischen Teile als IIFE, Symfony AssetMapper verwaltet alles andere.
| Aufgabe | Webpack Encore | Symfony AssetMapper | Unterschied |
|---|---|---|---|
| Paket hinzufügen | npm install paket |
importmap:require paket |
Kein node_modules, kein package.json |
| Build-Schritt | npm run build |
asset-map:compile |
Sekunden statt Minuten |
| Entwicklungsmodus | Watcher-Prozess nötig | Kein Watcher nötig | Änderungen sofort sichtbar |
| Versioning | Webpack contenthash | Automatisch per Hash | Gleichwertig, ohne Konfiguration |
| Legacy CommonJS | Vollständig unterstützt | Nur ESM | Ältere Pakete ggf. problematisch |
9. AssetMapper vs. Webpack Encore im Vergleich
Symfony AssetMapper gewinnt bei Einfachheit, Wartbarkeit und Deployment-Geschwindigkeit gegenüber Webpack Encore. Der Wegfall von Node.js-Abhängigkeiten bedeutet weniger Versionskonflikte, weniger Breaking Changes durch npm-Updates und eine sauberere Projektstruktur. In Docker-basierten Deployments entfällt der separate Build-Container für Frontend-Assets — bin/console asset-map:compile läuft im PHP-Container und ist in Sekunden abgeschlossen. Das ist ein echter Gewinn für kleinere Teams, die keine dedizierte Frontend-Build-Infrastruktur betreiben wollen.
Webpack Encore bleibt überlegen, wenn das Projekt TypeScript mit komplexen Konfigurationen, CSS-Präprozessoren wie Sass oder Less, aggressive Code-Splitting-Strategien oder Abhängigkeiten auf CommonJS-only-Pakete benötigt. Für Projekte mit dedizierten Frontend-Entwicklern, die eine vollständige Build-Pipeline mit Linting, Testing und Transpilierung erwarten, liefert Webpack oder Vite mehr Kontrolle. Symfony AssetMapper richtet sich explizit an die Mehrheit der Symfony-Projekte, die modernes JavaScript benötigen, aber keine komplexe Build-Pipeline rechtfertigen können.
Mironsoft
Symfony-Entwicklung, Frontend-Modernisierung und AssetMapper-Migration
Webpack-Komplexität hinter euch lassen?
Wir migrieren Symfony-Projekte von Webpack Encore zu AssetMapper — Analyse der bestehenden Assets, ESM-Umstellung, Stimulus-Integration und saubere Deployment-Pipeline ohne Node.js-Overhead.
Migration
Analyse bestehender Webpack-Konfiguration, ESM-Umstellung und Import-Map-Aufbau
Stimulus-Integration
Symfony UX-Komponenten und Stimulus-Controller ohne Build-Schritt einrichten
Deployment
asset-map:compile in CI/CD-Pipeline integrieren und CDN-Caching einrichten
10. Zusammenfassung
Symfony AssetMapper macht den Node.js-Bundler für die meisten Symfony-Projekte überflüssig. Import Maps ermöglichen native ES-Module-Auflösung im Browser ohne Webpack-Konfiguration. Vendor-Pakete werden per importmap:require heruntergeladen und lokal ausgeliefert — ohne node_modules, ohne package.json. Automatisches Versioning durch Content-Hashes ermöglicht aggressives Browser-Caching ohne Konfigurationsaufwand. Stimulus und das gesamte Symfony UX-Ökosystem funktionieren ohne Build-Schritt. Deployments werden schneller, einfacher und unabhängiger von Node.js-Versionen.
Der Wechsel lohnt sich für alle Symfony-Projekte, die kein komplexes Build-Setup benötigen: traditionelle Webanwendungen, E-Commerce-Systeme, CMS-Projekte und APIs mit Administrationsoberflächen. Webpack Encore bleibt die richtige Wahl, wenn TypeScript, Sass oder Legacy-CommonJS-Pakete unverzichtbar sind. Für alle anderen Projekte ist Symfony AssetMapper der direkteste Weg zu modernem JavaScript ohne Bundler-Komplexität.
Symfony AssetMapper — Das Wichtigste auf einen Blick
Kein Bundler nötig
Import Maps + ES-Module im Browser ersetzen Webpack für die meisten Symfony-Projekte. Kein npm, kein node_modules, kein Build-Watcher.
Vendor-Pakete per CLI
bin/console importmap:require paket lädt Pakete von jsDelivr und trägt sie in die Import Map ein. importmap:install stellt nach git clone wieder her.
Automatisches Versioning
Content-Hashes für alle Assets ohne Konfiguration. asset() in Twig löst automatisch den versionierten Pfad auf.
Stimulus & UX
Symfony UX-Komponenten und Stimulus-Controller funktionieren vollständig ohne Build-Schritt. Controller-Auto-Discovery inklusive.