Skip to Content

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_modules en prod). Il s’appuie sur les importmaps et les modules ES natifs des navigateurs.
  • Vos assets vivent dans assets/ ; importmap.php dé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:compile fige 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'importmap

Le 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.js

Ces 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) et npm install. AssetMapper remplace le workflow npm pour le front. Si vous voyez un projet avec importmap.php, ne cherchez pas de package.json front : les dépendances JS sont dans importmap.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ée

Il 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 JSAucun (modules ES + importmap)Étape de build (webpack)
node_modulesNonOui
Cas idéalBack-offices, sites, la plupart des appsBuild front complexe (JSX lourd, transformations poussées)
TendanceRecommandé par défautLegacy / cas avancés

Depuis Symfony 5 : à votre époque, Webpack Encore était le standard front de Symfony (avec node_modules et 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 ?

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.