Chapitre 7.3 — AssetMapper
Partie 7 : Twig & back-office — Chapitre 3/5 Version de référence : Symfony AssetMapper / Symfony 7.4.
⏱️ TL;DR
- AssetMapper sert du CSS/JS moderne sans bundler (pas de Webpack, pas de
node_modulesen prod). Il s’appuie sur les importmaps et les modules ES natifs des navigateurs.- Vos assets vivent dans
assets/;importmap.phpdéclare les dépendances JS ;{{ importmap() }}dans le template injecte tout.- On ajoute une lib JS avec
php bin/console importmap:require bootstrap(elle est téléchargée et versionnée localement, pas via un CDN à l’exécution).- Stimulus et Turbo (Partie 8) s’installent via AssetMapper. Tailwind aussi (via un bundle dédié).
- En prod,
asset-map:compilefige les assets (versionnés, cache-busting).- Pour un dev Next.js : c’est l’anti-bundler — pas de build JS, on sert des modules ES directement, façon « import maps ». Déroutant au début, très simple ensuite pour un back-office.
🎯 Objectifs
- Comprendre le modèle « sans bundler » d’AssetMapper.
- Ajouter des dépendances JS et du CSS.
- Intégrer Stimulus/Turbo et Tailwind.
- Compiler les assets pour la production.
1. Le problème des assets, et le pari d’AssetMapper
Historiquement, servir du JS/CSS moderne imposait un bundler (Webpack, Vite) : un node_modules, une étape de build, de la configuration. AssetMapper fait le pari inverse : les navigateurs modernes savent charger des modules ES natifs et résoudre des dépendances via des importmaps — donc plus besoin de bundler pour beaucoup de cas.
Résultat : pas d’étape de build en dev, pas de node_modules à déployer. Vous éditez un fichier JS, il est servi tel quel.
2. La structure
assets/
├── app.js ← point d'entrée JS
├── styles/
│ └── app.css ← CSS
└── controllers/ ← contrôleurs Stimulus (Partie 8)
importmap.php ← déclare les dépendances JS (versionnées)Le point d’entrée app.js importe le CSS et les libs :
// assets/app.js
import './styles/app.css';
import 'bootstrap'; // résolu via l'importmapLe template de base branche tout avec {{ importmap() }} :
{# templates/base.html.twig — dans le <head> #}
{% block javascripts %}
{{ importmap('app') }} {# injecte l'importmap + charge assets/app.js #}
{% endblock %}3. Ajouter une dépendance JS
On n’installe pas via npm. On utilise la commande AssetMapper, qui télécharge la lib et la versionne localement :
php bin/console importmap:require bootstrap
php bin/console importmap:require chart.jsCes commandes ajoutent des entrées dans importmap.php. La lib est stockée dans assets/vendor/ et servie depuis votre domaine (pas un CDN tiers à l’exécution — meilleure fiabilité et confidentialité). Pour référencer un asset (image, CSS) dans un template : la fonction asset().
<img src="{{ asset('images/logo.png') }}" alt="BookLab">⚠️ Piège : ne mélangez pas
importmap:require(AssetMapper) etnpm install. AssetMapper remplace le workflow npm pour le front. Si vous voyez un projet avecimportmap.php, ne cherchez pas depackage.jsonfront : les dépendances JS sont dansimportmap.php.
4. Stimulus & Turbo via AssetMapper
Symfony UX (Partie 8) s’intègre naturellement :
composer require symfony/ux-turbo # Turbo (navigation SPA-like)
composer require symfony/stimulus-bundle # Stimulus (petits contrôleurs JS)Ces bundles branchent automatiquement leurs assets dans l’importmap. Vos contrôleurs Stimulus vont dans assets/controllers/ et sont auto-chargés. On les détaille au chapitre 8.1.
5. Tailwind avec AssetMapper
Tailwind nécessite une étape de compilation CSS (il génère le CSS depuis vos classes). Le bundle symfonycasts/tailwind-bundle l’intègre sans Node :
composer require symfonycasts/tailwind-bundle
php bin/console tailwind:init
php bin/console tailwind:build --watch # en dev, recompile à la voléeIl télécharge le binaire standalone de Tailwind (pas de node_modules), et compile assets/styles/app.css. Vous écrivez vos classes Tailwind dans les templates Twig comme d’habitude.
💡 Pour un dev Next.js : Tailwind, vous connaissez. La différence ici : aucun Node dans la boucle — le bundle utilise le binaire autonome de Tailwind. Pour un back-office Symfony, c’est un combo très efficace : Tailwind pour le style, Twig pour le HTML, Stimulus pour les interactions, zéro build JS.
6. Compiler pour la production
En prod, on fige les assets (versionnés pour le cache-busting) :
php bin/console asset-map:compile # copie/hash les assets dans public/assets/Chaque asset reçoit un hash dans son nom (app-3f9a....js) : quand le contenu change, l’URL change, forçant le navigateur à recharger (fin des problèmes de cache périmé). AssetMapper gère ce versioning automatiquement.
7. AssetMapper vs Webpack Encore : lequel ?
| AssetMapper (défaut moderne) | Webpack Encore | |
|---|---|---|
| Build JS | Aucun (modules ES + importmap) | Étape de build (webpack) |
node_modules | Non | Oui |
| Cas idéal | Back-offices, sites, la plupart des apps | Build front complexe (JSX lourd, transformations poussées) |
| Tendance | Recommandé par défaut | Legacy / cas avancés |
⚡ Depuis Symfony 5 : à votre époque, Webpack Encore était le standard front de Symfony (avec
node_moduleset build). AssetMapper (2023+) est désormais l’approche par défaut et couvre l’immense majorité des besoins. Encore reste disponible pour les builds vraiment complexes, mais pour un back-office moderne, AssetMapper est plus simple. Si vous croisez Encore sur un projet ancien, c’est la génération précédente.
⚠️ Piège : AssetMapper sert des modules ES individuels (pas de bundle unique). Sur de très nombreux petits fichiers et une connexion lente en HTTP/1.1, ça peut multiplier les requêtes. En prod, servez en HTTP/2/3 (FrankenPHP le fait — Partie 15) qui multiplexe les requêtes : le « pas de bundle » cesse d’être un problème.
✏️ Exercices
Exercice 1. Vous voulez ajouter la librairie chart.js à votre back-office. Quelle commande, et où la lib est-elle servie ?
✅ Solution
php bin/console importmap:require chart.js. La lib est téléchargée, versionnée localement (dans assets/vendor/) et servie depuis votre propre domaine via l’importmap — pas depuis un CDN tiers à l’exécution. On l’importe ensuite dans assets/app.js (import Chart from 'chart.js').
Exercice 2. Un collègue cherche le package.json du front d’un projet Symfony 7.4 et ne le trouve pas. Que lui expliquez-vous ?
✅ Solution
Le projet utilise AssetMapper (pas de bundler, pas de node_modules). Les dépendances JS front sont déclarées dans importmap.php (via importmap:require), pas dans un package.json. Le front est servi en modules ES natifs + importmap, sans étape de build. (Un package.json peut exister pour d’autres outils, mais pas pour gérer les dépendances front façon Webpack.)
Exercice 3. Pourquoi la compilation prod (asset-map:compile) ajoute-t-elle un hash au nom des fichiers ?
✅ Solution
Pour le cache-busting : le hash dépend du contenu du fichier. Quand le contenu change, le nom (donc l’URL) change, ce qui force le navigateur à télécharger la nouvelle version au lieu de servir une version cachée périmée. Les fichiers inchangés gardent leur nom et restent en cache. AssetMapper gère ce versioning automatiquement.
🧠 Quiz de révision
1. Quelle est l’idée centrale d’AssetMapper ?
Servir du JS/CSS moderne sans bundler, via les modules ES natifs et les importmaps — pas de Webpack, pas de node_modules, pas d’étape de build en dev.
2. Comment ajoute-t-on une dépendance JS ?
php bin/console importmap:require <lib> : elle est téléchargée, versionnée localement et servie depuis votre domaine (déclarée dans importmap.php).
3. Comment intègre-t-on Tailwind sans Node ?
Avec symfonycasts/tailwind-bundle (binaire Tailwind autonome) : tailwind:init puis tailwind:build --watch. Pas de node_modules.
4. Que fait asset-map:compile en prod ?
asset-map:compile en prod ?Il fige et versionne (hash) les assets dans public/assets/ pour le cache-busting.
5. AssetMapper ou Encore par défaut aujourd’hui ?
AssetMapper (défaut moderne, sans build). Encore reste pour les builds front vraiment complexes (legacy/cas avancés).
Prochain chapitre : 7.4 — Back-office à la main — construire le CRUD de BookLab en Twig.