• 30 hours
  • Medium

Free online content available in this course.

Videos available in this course

Certificate of achievement available at the end this course

Got it!

Last updated on 5/13/19

Utiliser Assetic pour gérer les codes CSS et JS de votre site

Log in or subscribe for free to enjoy all this course has to offer!

La gestion des ressources CSS et JavaScript dans un site Internet est très importante et n'est pas si évidente ! Leur chargement est très souvent le point le plus lent pour l'affichage de la page à vos visiteurs, ce n'est donc pas quelque chose à négliger.

Pour vous aider à gérer ces ressources efficacement, Symfony intègre un bundle nommé Assetic qui va s'occuper de tout cela à votre place. Il va vous permettre d'optimiser au maximum le chargement de ces ressources pour vos visiteurs. Vous verrez, ce bundle est presque magique !

Théorie : entre vitesse et lisibilité, pourquoi choisir ?

À propos du nombre de requêtes HTTP d'une page web

Vous devez sûrement vous demander ce que vient faire la vitesse d'une page dans une section qui traite de code CSS. C'est une bonne question et je vais y répondre. Le temps de chargement ressenti d'une page par un visiteur comprend tout le processus du clic au rendu de la page par le navigateur. Ainsi, on y inclut :

  • Le temps d'envoi de la requête au serveur lors du clic. On ne peut pas y faire grand-chose, malheureusement.

  • Le temps d'exécution de la page côté serveur, le temps PHP, donc. Pour cela, il faut bien penser son script et essayer de l'optimiser un peu.

  • Le temps d'envoi du code HTML par le serveur vers le navigateur. On ne peut pas y faire grand-chose non plus.

  • Mais là ce n'est pas tout : à partir de cette page HTML que le navigateur reçoit, ce dernier doit tout recommencer pour chaque fichier CSS, chaque JavaScript et chaque image !

Donc si votre page contient 5 fichiers CSS, 3 JavaScript et 15 images, cela fait un total de 23 requêtes HTTP à traiter par votre navigateur pour vous afficher l'intégralité de la page ! Et pour ces 23 requêtes, il y a les temps d'envoi et de réception qui sont incompressibles et qui prennent du temps.

Au final, s'il faut bien sûr optimiser le code PHP côté serveur, la partie front-end qui comprend codes HTML, CSS et JavaScript ainsi que les fichiers images est bien celle qui prend le plus de temps à se charger, vu du visiteur.

Comment optimiser le front-end ?

L'idée est de réduire les temps incompressibles. Comme ils sont justement incompressibles, il faut que l'on en diminue le nombre. La seule solution est donc de grouper ces fichiers. L'idée est que, au lieu d'avoir cinq fichiers CSS différents, on va mettre tout notre code CSS dans un seul fichier. Comme cela, on aura une seule requête au lieu de cinq. Super !

Mais le problème, c'est que si l'on avait trois fichiers et non un seul, ce n'était pas pour rien. Chaque fichier concernait une partie de votre site, c'était bien plus lisible. Tout regrouper vous gênerait dans le développement de vos fichiers CSS (idem pour les fichiers JavaScript, bien sûr).

C'est là qu'Assetic va intervenir : il va grouper lui-même les fichiers et va vous permettre de garder votre séparation !

Il est aussi possible d'améliorer le temps de chargement !

En effet, transmettre votre unique fichier CSS de plusieurs centaines de lignes, cela prend du temps (temps qui varie en fonction de la connexion de votre serveur, de celle du visiteur, etc.). On peut améliorer ce temps en diminuant simplement la taille du fichier.

C'est possible grâce à un outil Java appelé YUI Compressor, un outil développé par Yahoo!. Cet outil permet de diminuer la taille de vos fichiers CSS, mais surtout de vos fichiers JavaScript, en supprimant les commentaires, les espaces, en raccourcissant le nom des variables, etc. On dit qu'il « minifie » les fichiers (il ne les compresse pas comme un fichier zip). Le code devient bien sûr complètement illisible ! Mais c'est là qu'Assetic intervient de nouveau : il vous permet de garder votre version claire lorsque vous développez, mais « minifie » les fichiers pour vos visiteurs (en mode prod) !

En action !

Vous voulez voir ce que donne l'utilisation d'Assetic sur un vrai site internet pour bien vous rendre compte ? Je vous invite à regarder la source d'un site que j'ai réalisé, Caissin.fr, dans lequel j'utilise Assetic. Le chargement de tous les fichiers CSS se fait en 3 lignes :

<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css">
<link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.min.css">
<link href="/assets/css/style.css">

Ce qui nous intéresse, c'est le dernier fichier, que j'ai nommé style.css. C'est ce fichier qui contient tous mes CSS perso. Ouvrez-le, vous pouvez voir que son contenu est difficilement lisible : pas d'indentation, pas d'espaces, etc. C'est cela qu'on appelle la « minification ». Vous pouvez également voir qu'il y a plusieurs fichiers concaténés en un seul. Bref, ce fichier est très dense et permet d'optimiser le chargement de tous les CSS du site, efficace !

Il est est de même avec le fichier Javascript, je vous laisse regarder ce que cela donne.

Conclusion

Grâce à Assetic, on peut optimiser très facilement nos scripts CSS/JS. Par exemple, nous pouvons passer de nos huit requêtes pour 500 Ko à seulement deux requêtes (1 CSS + 1 JS) pour 200 Ko. Le temps d'affichage de la page pour nos visiteurs sera donc bien plus court, et on conserve la lisibilité du code côté développeur !

Pratique : Assetic à la rescousse !

L'objectif d'Assetic est de regrouper nos fichiers CSS et JavaScript comme nous venons d'en parler. Il n'est pas inclus par défaut avec Symfony, il nous faut donc l'installer ainsi que ses dépendances.

Installer Assetic et les bibliothèques de compression

Commençons par ajouter les dépendances dans notre composer.json  :

"require": {
    "symfony/assetic-bundle": "^2.7.1",
    "leafo/scssphp": "~0.6",
    "patchwork/jsqueeze": "~1.0"
},

Et mettez à jour vos dépendances avec un php composer.phar update.

Puis, ajoutez la configuration minimale du bundle AsseticBundle dans votre fichier config.yml :

# app/config/config.yml

assetic:
  debug:          '%kernel.debug%'
  use_controller: '%kernel.debug%'

Servir des ressources

Assetic peut servir au navigateur les ressources que vous lui demandez.

Servir une seule ressource

Allez donc dans la vue du layout, nous allons y déclarer nos fichiers CSS et JavaScript. Voici comment on déclarait nos fichiers CSS jusqu'à maintenant :

{# src/OC/CoreBundle/Resources/views/layout.html.twig #}
{# ou n'importe quelle vue en réalité ! #}

<link rel="stylesheet" href="{{ asset('bundles/ocplatform/css/main.css') }}" type="text/css" />

Et voici comment faire pour décharger cette responsabilité à Assetic :

{% stylesheets 'bundles/ocplatform/css/main.css' %}
  <link rel="stylesheet" href="{{ asset_url }}" type="text/css" />
{% endstylesheets %}

Et voici le HTML qu'Assetic a généré avec cette balise :

<link rel="stylesheet" href="/Symfony/web/app_dev.php/css/519c4f6_main_1.css" type="text/css" />

Pas convaincant ? C'est parce que nous sommes en mode dev ! Nous verrons plus loin comment nous occuper du mode prod, qui demande un peu plus d'effort.

En attendant, essayons de comprendre ce code généré. En mode dev, Assetic génère à la volée les ressources, d'où une URL vers un fichier CSS qui passe par le contrôleur frontal app_dev.php. En réalité, c'est bien un contrôleur d'Assetic qui s'exécute, car le fichier app_dev.php/css/519c4f6_main_1.css n'existe évidemment pas. Ce contrôleur va chercher le contenu du fichier qu'on lui a indiqué, puis le retransmet. Pour l'instant il le retransmet tel quel, mais il sera bien sûr possible d'appliquer des modifications, nous le verrons par la suite.

Et bien sûr, le mécanisme est exactement le même pour vos fichiers JavaScript :

{% javascripts 'bundles/ocplatform/js/main.js' %}
  <script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
Servir plusieurs ressources regroupées en une

Cela devient déjà un peu plus intéressant. En plus du fichier CSS main.css (ou tout autre fichier, adaptez au code CSS que vous avez bien sûr), disons qu'on veut charger un deuxième fichier CSS platform.css (ou n'importe quel autre CSS que vous souhaitez utiliser bien sûr). Avec l'ancienne méthode, on aurait écrit une deuxième balise <link>, mais voici comment faire avec Assetic :

{% stylesheets
  'bundles/ocplatform/css/main.css'
  'bundles/ocplatform/css/platform.css' %}
  <link rel="stylesheet" href="{{ asset_url }}" type="text/css" />
{% endstylesheets %}

On a simplement rajouté la deuxième ressource à charger dans la balise stylesheets. Et voici le rendu HTML :

<link rel="stylesheet" href="/Symfony/web/app_dev.php/css/03b7e21_main_1.css" type="text/css" />
<link rel="stylesheet" href="/Symfony/web/app_dev.php/css/03b7e21_platform_2.css" type="text/css" />

Mais, il n'était pas censé regrouper les deux ressources en une ?

Si bien sûr… mais en mode prod ! Encore une fois, nous sommes en mode de développement, il est donc inutile de regrouper les ressources (on se fiche un peu de la rapidité), Assetic ne le fait donc pas.

Si vous avez plusieurs fichiers CSS dans le répertoire des CSS de votre bundle, il est également possible d'utiliser un joker pour les charger tous. Ainsi, au lieu de préciser les fichiers exacts, vous pouvez utiliser le joker « * », comme ceci :

{% stylesheets 'bundles/ocplatform/css/*' %}

Ce qui chargera tous les fichiers qui sont dans le répertoire, pratique !

Modifier les ressources servies

En servant les ressources depuis un contrôleur PHP, Assetic a la possibilité de modifier à la volée tout ce qu'il sert. Cela est possible grâce aux filtres, que l'on peut définir directement dans les balises stylesheets ou javascripts.

Voyons quelques filtres intéressants.

Le filtre cssrewrite

Si vous avez exécuté le code précédent, vous avez pu vous rendre compte qu'il se pose un petit problème lorsque vous utilisez des images dans le CSS. En effet, imaginons que votre CSS fait référence aux images via un chemin relatif ../img/exemple.png.

Lorsque le fichier CSS était placé dans web/bundles/xxx/css, ce chemin relatif pointait bien vers web/bundles/xxx/img, là où sont nos images. Or maintenant, du point de vue du navigateur, le fichier CSS est dans app_dev.php/css, du coup le chemin relatif vers les images n'est plus bon !

C'est ici qu'intervient le filtre cssrewrite. Voici la seule modification à apporter côté vue Twig :

{% stylesheets filter='cssrewrite'
  'bundles/ocplatform/css/main.css'
  'bundles/ocplatform/css/platform.css' %}
  <link rel="stylesheet" href="{{ asset_url }}" type="text/css" />
{% endstylesheets %}

On a juste précisé l'attribut filter à la balise. Ce filtre permet de réécrire tous les chemins relatifs contenus dans les fichiers CSS, afin de prendre en compte la modification du répertoire du CSS.

Puis, activez le filtre cssrewrite  dans la configuration :

# app/config/config.yml

assetic:
  debug:          '%kernel.debug%'
  use_controller: '%kernel.debug%'
  filters:
    cssrewrite: ~

Actualisez votre page, vous verrez que cela fonctionne très bien ! Le chemin relatif d'accès aux images est devenu : ../../bundles/ocplatform/img/exemple.png, ce qui est correct.

Les filtres scssphp et jsqueeze

Ces filtres sont très utiles, ce sont ceux qui « minifient » les fichiers.

Ces outils scssphp et jsqueeze sont ceux qu'on a téléchargé grâce à Composer un peu plus haut, leur code se trouve donc dans notre répertoire vendor. Maintenant, direction la configuration de notre application pour activer et configurer ces filtres :

# app/config/config.yml

assetic:
  debug:          '%kernel.debug%'
  use_controller: '%kernel.debug%'
  filters:
    cssrewrite: ~
    jsqueeze:   ~
    scssphp:
      formatter: 'Leafo\ScssPhp\Formatter\Compressed'

Voilà, nous venons d'activer les filtres scssphp et jsqueeze, on peut maintenant les utiliser depuis nos vues. Ajoutez ce filtre dans vos balises :

{% stylesheets  filter='cssrewrite, scssphp'
  ... %}

Et de même pour les fichiers JavaScript :

{% javascripts filter='jsqueeze'
  ... %}

Testez le rendu !

Mais… on est toujours en mode dev et les fichiers CSS et JS sont devenus illisibles pour un éventuel débogage ! Heureusement, vous avez la possibilité de dire qu'un filtre ne s'applique pas en mode dev. Il suffit de mettre un point d'interrogation devant :

{% stylesheets filter='?scssphp'
  ... %}

Ainsi, le filtre ne s'appliquera qu'en mode prod, tout comme le groupement des fichiers en un seul.

Au final, notre mode dev n'a pas changé d'un poil, on garde nos différents fichiers et ces derniers sont lisibles, mais le mode prod a reçu toutes les optimisations : regroupement des fichiers ainsi que « minification ».

Gestion du mode prod

Si vous n'avez pas encore testé le rendu en mode prod, faites-le. Cela ne fonctionne pas ? Vos fichiers CSS et JS ne sont pas chargés ? C'est normal. :p Nous n'avons pas fini notre mise en place.

Comprendre Assetic

Pour comprendre pourquoi la gestion du mode prod demande un effort supplémentaire, vous devez comprendre la manière dont Assetic fonctionne. Lorsque l'on utilise les balises {% stylesheets %} ou {% javascripts %}, le code HTML généré en mode prod est le suivant (regardez la source de vos pages HTML) :

<link rel="stylesheet" href="/Symfony/web/css/cd91cad.css" type="text/css" />

Or ce fichier n'existe pas du tout !

Lors du mode dev, on l'a vu, Assetic passe directement par un contrôleur pour générer à la volée nos ressources. Mais évidemment, « minifier » et regrouper des fichiers à la volée et ce pour chaque requête, cela prend beaucoup de temps. Si en mode dev on peut se le permettre, on ne le peut pas en mode prod !

Du coup, l'astuce pour le mode prod est d'exporter en dur, une bonne fois pour toutes, les fichiers CSS et JS dont on a besoin. Ainsi, en mode prod, le fichier /css/cd91cad.css (dans mon cas) existera en dur, Assetic n'interceptera pas l'URL, et votre serveur web (souvent Apache) va envoyer directement le contenu du fichier à vos visiteurs. Plus rapide, on ne peut pas !

Exporter ses fichiers CSS et JS

Pour faire cet export en dur, il faut utiliser une simple commande d'Assetic :

php bin/console assetic:dump --env=prod

Cette commande devrait vous sortir un résultat de ce type :

C:\wamp\www\Symfony>php bin/console assetic:dump --env=prod
Dumping all prod assets.
Debug mode is off.

16:13:30 [file+] C:/wamp/www/Symfony/app/../web/css/cd91cad.css

Cette commande va lire toutes nos vues pour y trouver les balises {% stylesheets %} et {% javascripts %}, puis va exporter en dur dans les fichiers /web/css/XXX.css et /web/js/XXX.js.

Et voilà, maintenant, nos fichiers existent réellement. Testez à nouveau le rendu en mode prod : c'est bon !

Et bien plus encore…

Assetic, c'est une bibliothèque complète qui permet beaucoup de choses. Vous pouvez également optimiser vos images, et construire une configuration plus poussée. Bref, n'hésitez pas à vous renseigner sur la documentation officielle.

En réumé

  • Le chargement des fichiers CSS et JS prend beaucoup de temps dans le rendu d'une page HTML sur le navigateur de vos visiteurs ;

  • Assetic permet de regrouper tous vos fichiers CSS ainsi que tous vos fichiers JS, afin de réduire le nombre de requêtes HTTP que doivent faire vos visiteurs pour afficher une page ;

  • Assetic permet également de minifier vos fichiers, afin de diminuer leur taille et donc accélérer leur chargement pour vos visiteurs ;

  • Enfin, l'utilisation d'Assetic permet de garder votre confort de développement en local, vos fichiers ne sont ni regroupés, ni minifiés : indispensable pour déboguer !

  • Le code du cours tel qu'il doit être à ce stade est disponible sur la branche iteration-22 du dépot Github.

Example of certificate of achievement
Example of certificate of achievement