Pour faire suite à notre précédent article sur la mise en place de votre chaîne de test avec Grunt, nous allons aborder la “génération” de votre application avec un code optimisé.

 

Présentation de usemin

Usemin est un outil qui s’occupe de remplacer, dans votre code html, les références à des fichiers CSS et JS non optimisés. Il s’occupe de générer la configuration de différents plugins Grunt et de déplacer/modifier les fichiers pour les traiter.

Pour faire notre version, nous allons donc passer par les étapes suivantes:

  • concaténation et minification des fichiers CSS et JS
  • compilation des fichiers less en CSS
  • copie des fichiers “statiques” (pages html, fonts, images)
  • génération d’un nom unique pour les images, CSS et JS

Tâches principales

Usemin déclare 2 taches :

  • useminPreprare qui s’occupe de générer la configuration des différents plugins Grunt; pour cela il y a une notion de répertoire source et répertoire destination, ce qui permet de ne pas modifier directement son code source
  • usemin qui remplace les références vers les ressources dans les fichiers html

Pour chaque plugin, Usemin va générer une Target ‘generated’ à l’intérieur de chaque tâche, qu’il faudra ensuite exécuter entre l’étape useminPreprare et usemin.

Plugins supportés par Usemin

Usemin est capable d’utiliser et de configurer les plugins Grunt suivants:

  • concat qui concatène des fichiers JS et CSS
  • uglify qui minifie les fichiers JS.
  • cssmin qui minifie les fichier CSS.
  • filerev qui génère des noms de fichier unique pour les fichiers de ressources

Pour la compilation des fichiers less, nous ajouterons une tâche de configuration dans Usemin, et pour la copie des fichiers statiques, nous configurerons la tâche de manière statique.

Installation des packages npm

Il faut que vous installiez les packages suivants:

  • less-plugin-clean-css
  • less-plugin-autoprefix
  • grunt-usemin
  • grunt-contrib-concat
  • grunt-contrib-cssmin
  • grunt-contrib-uglify
  • grunt-contrib-copy
  • grunt-filerev
  • grunt-contrib-less
  • grunt-contrib-clean

Pour rappel, cela peut se faire directement dans le fichier ‘package.json’ (suivi d’un ‘npm install’) ou bien en passant par la commande ”npm install PACKAGE_NAME –save” .

 

Mise en place de Usemin

Etapes préparatoires

Mise à jour des variables globales

Il nous faut tout d’abord ajouter les variables que l’on va utiliser dans le reste du Gruntfile :

Modification de la tâche ‘build’

Modifiez votre tâche build de la façon suivante :

Nous avons maintenant le déroulé suivant :

  1. testing: validation du code Typescript et compilation en Javascript
  2. copy: copie des ressources statiques dans le dossier de destination
  3. useminPrepare: génération de la configuration des tâches
  4. *:generated: exécution des différentes tâches via la Target ‘generated’
  5. filerev: renommage des ressources avec un nom unique basé sur le contenu du fichier (basé sur le md5)
  6. usemin: remplacement des références vers les ressources dans les fichiers html

Tache ‘copy’

Cette tâche est simple. Nous voulons copier nos fichiers statiques vers le répertoire de distrib. Nous avons une règle spéciale pour les fonts fournies par Bootstrap car ce dernier les référence depuis ses fichiers CSS, que nous concaténons. Il faut donc bien penser à copier ces ressources car Usemin ne le fera pas pour vous.

Ajoutez la tâche suivante dans votre Gruntfile.

Tache ‘useminPrepare’

Voila le code à ajouter dans votre Gruntfile, nous allons l’expliquer juste après.

Détection des fichiers à traiter

On peut spécifier soit même le nom des fichiers css et js à traiter par Usemin mais le plus intéressant est de le laisser explorer votre code html pour les trouver. Cela se fait avec la target ‘html’.

Pour que usemin sache quelles références traiter dans votre html, il faut définir ce qu’on appelle des Blocks à l’aide de commentaires dans votre fichier html. Le format est le suivant :

Le type correspond au type de fichier configuré dans le flux de traitement de usemin (nous en parlerons plus en détail juste après). Le path correspond au fichier de destination.

A titre d’exemple, voila 2 blocks tirés de notre fichier index.html

Répertoire de destination

La configuration du répertoire de destination se fait par l’option ‘dest’. C’est là que Usemin placera les différents fichiers générés, même si pour certaines étapes intermédiaires, Usemin utilise un dossier ‘.tmp’.

Redéfinition du flux de traitement

Par défaut, Usemin sait traiter les JS et les CSS. Pour gérer les fichiers less, on pourrait simplement créer une tâche ‘less’ qui cible les fichiers en question, mais c’est beaucoup plus puissant et souple de configurer usemin pour qu’il analyse le html pour en extraire la liste de fichiers à traiter.

Pour cela, la première étape est de redéfinir le flow de Usemin (on ne peut pas simplement étendre le flux existant).
Les étapes ‘js’ et ‘css’ peuvent référencer les tâches pré-existantes, ‘concat’, ‘uglify’ et ‘cssmin’, par contre pour l’étape ‘less’ il nous faut expliquer à Usemin quoi faire. C’est ce que nous avons fait avec l’option ‘flow’.

Le paramètre ‘name’ permet de spécifier quelle tâche Grunt exécuter et le paramètre ‘createConfig’ est une fonction qui va s’occuper de créer la configuration de la tâche Grunt (ici la tache ‘less’). Pour une question de lisibilité,nous vous recommandons de sortir cette fonction du ‘flow’ de usemin.

Déclarez cette fonction en haut de votre Gruntfile, à coté de votre variable globale ‘globalCfg’ :

Cette fonction utilise 2 paramètres fournis par usemin.

  • context: un objet qui contient le contexte d’exécution de l’étape que usemin est entrain de traiter
  • block: un objet qui contient le block que usemin a extrait du fichier html (celui contenu entre <!-- build --> et <!-- endbuild --> )

Pour en savoir plus sur le sujet, vous pouvez vous référez à la doc usemin sur le createConfig.

Tâche concat

Ce travail se fait avec le plugin grunt-contrib-concat. Le but est de générer un fichier unique à télécharger par le navigateur pour limiter le nombre de requêtes réseau du browser web.

La configuration générée par usemin étant suffisante, la tâche n’est pas présente dans le Gruntfile. Elle est quand même utilisable par notre tâche de ‘build’ car une fois que Usemin a été exécuté, Grunt peut bien appeler ‘concat:generated’.

Tâche cssmin

Ce travail se fait avec le plugin grunt-contrib-cssmin (qui se charge d’appeler clean-css). Ce plugin va retirer tout ce qui est inutile dans le CSS pour réduire sa taille.

La configuration générée par Usemin étant suffisante, la tâche n’est pas présente dans le Gruntfile. Elle est quand même utilisable par notre tache de ‘build’ car une fois que Usemin a été exécuté, Grunt peut bien appeler ‘cssmin:generated’.

Tache uglify

L’objectif est de rendre votre code Javascript moche pour compliquer sa compréhension par les curieux, et au passage diminuer la taille du fichier en retirant les informations inutiles (commentaires, nom de variables plus court, formatage de code, …). Cela se fait avec le plugin grunt-contrib-uglify.

La configuration générée par Usemin étant suffisante, la tâche n’est pas présente dans le Gruntfile. Elle est quand même utilisable par notre tache de ‘build’ car une fois que Usemin a été exécuté, Grunt peut bien appeler ‘uglify:generated’.

Tache less

La compilation des fichiers less se fait avec le plugin grunt-contrib-less. Nous allons aussi activer 2 plugins spécifiques :

Autoprefixer

Autoprefixer s’occupe d’ajouter les préfixes des différents vendor pour vos règles CSS. Il permet donc de garder un code Less plus propre et d’éviter d’avoir à vérifier chaque commande CSS sur un site comme caniuse.
Attention par contre, si vous utilisez une règle CSS incompatible avec une partie des navigateurs que vous ciblez, il n’y aura aucune alerte.

Par exemple, pour le code suivant :

on obtient cette adaptation :

Configuration Grunt

Créez la tâche suivante votre Gruntfile:

Tache filerev

Le plugin grunt-filerev s’occupe de renommer les images, css et js pour éviter les problèmes de cache. Il génère un nom unique de fichier basé sur le nom original du fichier et sur son md5.

Il est intéressant de déclarer plusieurs Target dans la tache Grunt, une par dossiers à traiter, car cela permet d’avoir un feedback plus riche lors de l’exécution du ‘grunt build’.

Quand filerev s’exécute, il génère un dictionnaire de tous les fichiers qu’il a remplacé. Cela est stocké dans une variable ‘grunt.filerev.summary’. De cette façon, quand Usemin est appelé, il sait comment remplacer les références (désormais invalides) vers les ressources.

Ajoutez la tâche suivante dans votre Gruntfile :

Tâche usemin

C’est la tâche finale pour packager notre release. Usemin va parcourir votre html présent dans le répertoire de distrib pour remplacer les différentes références aux ressources.

Pour les fichiers css et jss, usemin va remplacer tout le Block par sa version concaténée et minifiée.
Pour les fichiers Less, qui ne sont pas gérés nativement par Usemin, nous devons préciser comment remplacer les Blocks. Vous devez fournir une fonction de traitement par l’option ‘blockReplacements’.
Pour les autres ressources, Usemin va vérifier dans l’objet ‘grunt.filerev.summary’ si cette dernière n’a pas été renommée. Si c’est le cas, Usemin vérifie dans la liste de dossiers de ressources (configuré par l’option ‘assetsDirs’) si le fichier existe.

 

Conlusion

Vous pouvez maintenant lancer la commande ‘grunt build’ pour packager votre application vers le dossier ‘dist’ et ensuite utiliser la commande ‘grunt web’ pour tester le résultat.

Vous pouvez retrouver le projet complet sur le git TypescriptAngularStarter et le détail du fichier gruntfile.

Partager