Pendant des années, ajouter un peu de JavaScript à un projet Symfony imposait d'installer Node.js, npm, Webpack Encore et des centaines de paquets dans node_modules, puis de lancer une compilation à chaque modification. Pour beaucoup de sites, c'était disproportionné. Depuis Symfony 6.3, le composant AssetMapper propose une autre voie : utiliser directement les capacités des navigateurs modernes, sans étape de build ni Node.js. Je l'utilise désormais sur la plupart de mes projets Symfony. Voici comment il fonctionne et quand le choisir.
Le principe d'AssetMapper
AssetMapper repose sur deux fonctionnalités désormais disponibles dans tous les navigateurs :
- Les modules JavaScript natifs (
importetexport), qui permettent de découper le code en fichiers sans outil de regroupement ; - Les import maps, qui indiquent au navigateur où trouver un module à partir de son nom, par exemple que
import Chart from 'chart.js'correspond à tel fichier.
Le rôle d'AssetMapper est d'organiser tout cela côté serveur : il expose les fichiers du dossier assets/, ajoute une empreinte de version dans leur nom pour le cache, et génère l'import map dans la page.
Installation et premiers pas
Dans un projet Symfony récent, AssetMapper est installé par défaut avec le pack webapp. Sinon :
composer require symfony/asset-mapper symfony/asset symfony/twig-pack
La recette Flex crée un fichier assets/app.js, un fichier importmap.php et ajoute dans le gabarit de base :
{% block javascripts %}
{% block importmap %}{{ importmap('app') }}{% endblock %}
{% endblock %}
Vous écrivez votre JavaScript dans assets/ comme d'habitude, avec des import entre fichiers. En développement, les fichiers sont servis directement : une modification est visible au rechargement de la page, sans compilation.
Ajouter une bibliothèque tierce
Plutôt que npm install, on utilise une commande de la console Symfony :
php bin/console importmap:require chart.js
La bibliothèque est téléchargée depuis un CDN public dans le dossier assets/vendor/, puis référencée dans importmap.php. Elle est servie depuis votre propre serveur : aucune dépendance à un CDN externe en production, ce qui est préférable pour la performance comme pour le RGPD.
Deux commandes utiles au quotidien :
php bin/console importmap:outdated # bibliothèques à mettre à jour
php bin/console importmap:audit # vulnérabilités connues
Faites tourner l'audit régulièrement, comme composer audit côté PHP (voir mon article sur Composer).
Et le CSS ?
Le CSS fonctionne de la même façon : un fichier assets/styles/app.css importé depuis app.js est ajouté automatiquement à la page. Le CSS moderne gère nativement les variables, l'imbrication des règles et les container queries : pour beaucoup de projets, un préprocesseur n'est plus nécessaire.
Si vous tenez à Sass ou à Tailwind, des bundles dédiés (symfonycasts/sass-bundle, symfonycasts/tailwind-bundle) s'occupent de la compilation, toujours sans Node.js, à l'aide d'un exécutable autonome.
Le déploiement en production
En production, on compile une fois les fichiers dans public/assets/ :
php bin/console asset-map:compile
Chaque fichier reçoit une empreinte dans son nom (app-3f2a9c1.js). Le serveur web peut donc les mettre en cache pendant un an : à chaque modification, le nom change et le navigateur télécharge la nouvelle version. Avec nginx, une règle de cache HTTP sur le dossier /assets/ suffit.
AssetMapper ajoute aussi des balises modulepreload pour les modules importés par le point d'entrée : le navigateur les découvre et les télécharge en parallèle, sans attendre d'analyser chaque fichier.
AssetMapper ou Webpack Encore ?
| Besoin | AssetMapper | Webpack Encore |
|---|---|---|
| Site avec du JavaScript léger (Stimulus, Turbo) | Idéal | Surdimensionné |
| Pas de Node.js sur le serveur ni en local | Oui | Non |
| React ou Vue avec JSX ou fichiers .vue | Non adapté | Oui |
| TypeScript | Possible via un bundle dédié | Oui |
| Optimisation fine du code (tree-shaking) | Non | Oui |
Ce que j'y ai gagné
Sur mes projets Symfony, passer à AssetMapper a simplifié chaque étape :
- Installation : plus besoin d'installer une version précise de Node.js pour reprendre un projet, même des années plus tard ;
- Déploiement : une commande PHP de plus dans le script de mise en ligne, et plus de dossier
node_modulessur le serveur ; - Sécurité : beaucoup moins de dépendances, donc moins de failles potentielles dans la chaîne d'approvisionnement ;
- Performance : des fichiers petits, mis en cache longtemps, et un JavaScript limité au nécessaire.
La documentation officielle de Symfony détaille toutes les options. Pour un tour d'horizon des autres évolutions du framework, voir mon article sur les nouveautés de Symfony 7.
Vous avez un projet Symfony à créer ou à moderniser ? Je développe des applications sur mesure avec une architecture simple et durable : parlons-en.