Manipuler les assets avec Cecil

Dans cet article j’explique comment Cecil, mon générateur de site statique, permet de manipuler des assets, sans dépendances à des outils tiers.

<link rel="stylesheet" href="{{ asset('sass/styles.scss')|to_css|minify|fingerprint }}">

Les bases

Un asset est une ressource web, tel qu’un fichier CSS, JavaScript ou encore une image, permettant d’habiller ou de dynamiser un site web.

Ainsi, une feuille de styles peut être chargée en indiquant simplement le chemin vers le fichier correspondant :

<link rel="stylesheet" href="/css/styles.css">

Dans l’exemple ci-dessus l’URL vers le fichier de la feuille de styles est « en dur » dans le template HTML et c’est souvent suffisant dans la plupart des cas.

Néanmoins, on peut rapidement se poser les questions suivantes :

  • Comment compresser ma feuille de styles pour gagner en performance ?
  • Comment compiler ma feuille de styles au format Sass et modifier des variables ?
  • Comment informer les navigateurs web que ma feuille de style à été modifiée et ne pas demander aux internautes de « vider le cache » ?

Cecil, grâce à sa fonction asset() combinée à quelques filtres Twig, répond à ces besoins.

Créer un asset

Reprenons l’exemple précédent en y appliquant la fonction asset() :

<link rel="stylesheet" href="{{ asset('css/styles.css') }}">

On crée ainsi un objet « asset » à partir du fichier styles.css préalablement déposé dans le dossier static/css/ du projet.

Remarque

Dans un contexte d’affichage l’objet « asset » retournera le chemin web relatif (path) de la ressource.
Vous pouvez utiliser le filtre url pour manipuler l’URL générée, par exemple :

{{ asset('css/styles.css')|url({canonical:true}) }}

Minification

Le filtre minify réduit la taille d’un asset du type CSS ou JavaScript, en supprimant les espaces, retours à la ligne, etc.

Template :

<link rel="stylesheet" href="{{ asset('css/styles.css')|minify }}">

Rendu :

<link rel="stylesheet" href="/css/styles.min.css">

Compilation Sass

Le filtre to_css compile un asset de type Sass.

Template :

<link rel="stylesheet" href="{{ asset('sass/styles.scss')|to_css }}">

Rendu :

<link rel="stylesheet" href="/css/styles.css">

Il est possible de paramétrer les règles de compilation via le fichier de configuration du projet (config.yml par défaut) de la manière suivante :

assets:
  compile:
    style: expanded # expanded ou compressed
    import: [sass, node_modules] # liste des chemins importés, relatifs au dossier static/

Il est également possible de remplacer la valeur des variables :

assets:
  variables:
    primary: '#5a5a5a'

Documentation : https://cecil.app/documentation/configuration/#assets

Empreinte (fingerprint)

Le filtre fingerprint crée l’empreinte de la ressource (d’après son contenu) et complète le nom du fichier en conséquence.
Ainsi, si le fichier est modifié il aura une empreinte différente lors de la génération du site : le consommateur du fichier considérera donc que cette ressource est différente de celle qu’il a dans son cache et la téléchargera.

Template :

<link rel="stylesheet" href="{{ asset('css/styles.css')|fingerprint }}">

Rendu :

<link rel="stylesheet" href="/css/styles.e549285c8ffa8af5e6254263c98d4397.css">

Regroupement (bundle)

La fonction asset() peut également combiner une liste d’assets du même type.

Template :

<link rel="stylesheet" href="{{ asset(['css/styles-a.css','css/styles-b.css']) }}">

Rendu :

<link rel="stylesheet" href="/css/styles.css">

Par défaut le fichier bundle porte le nom suivant :

  • styles.css pour les fichiers CSS
  • scripts.js pour les fichiers JavaScript

Il est possible de personnaliser ce nom via l’option filename.

Template :

<link rel="stylesheet" href="{{ asset(['css/styles-a.css','css/styles-b.css'],{filename:'main.css'}) }}">

Rendu :

<link rel="stylesheet" href="/main.css">

Attributs d’un asset

D’autre part, un asset expose des attributs (en fonction de son type) :

  • file : Chemin du fichier local
  • path : Chemin web relatif
  • ext : Extension
  • type : Type de média (ex : image)
  • subtype : Sous-type de média (ex : image/jpeg)
  • size : Poids (en octets)
  • source : Contenu avant traitement
  • content : Contenu après traitement
  • integrity : Hachage d'intégrité
  • width : Largeur (dans le cas d’un fichier image)
  • height : Hauteur (dans le cas d’un fichier image)
  • audio : Tableau Mp3Info (dans le cas d’un fichier MP3)

Exemples :

{% set image = asset('image.jpg') %}
<img src="{{ image }}" width="{{ image.width }}" integrity="{{ image.integrity }}" crossorigin="anonymous">
Durée : {{ asset('title.mp3').audio.duration|round }} min

Documentation : https://cecil.app/documentation/templates/#attributes

Fichier distant

De plus, si le chemin passé à la fonction asset() est une URL, le fichier sera téléchargé localement et mis en cache pour les prochaines générations.

Exemple :

{{ asset('https://cdnjs.cloudflare.com/ajax/libs/anchor-js/4.3.1/anchor.min.js') }}

Le fichier, lors de la génération du site, sera enregistré de la manière suivante :

/assets/cdnjs.cloudflare.com/ajax/libs/anchor-js/4.3.1/anchor.min.js

Paramétrage par défaut

Enfin, par défaut Cecil applique l’ensemble des traitements, désactivables via la configuration :

assets:
  compile:
    enabled: true # compile automatiquement un fichier Sass
  minify:
    enabled: true # minifie automatiquement un fichier CSS ou JavaScript
  fingerprint:
    enabled: true # applique automatiquement l'empreinte du fichier à son nom

Template :

<link rel="stylesheet" href="{{ asset('sass/styles.scss') }}">

Rendu :

<link rel="stylesheet" href="/css/styles.e549285c8ffa8af5e6254263c98d4397.min.css">