Bonnes pratiques : Automatiser ses tâches avec Grunt

Coup de coeur, Tech, Tutoriel

Le temps de chargement d’une application web est crucial. La lenteur du chargement de l’application n’est pas seulement due au temps du réponse du module back-end ou d’un appel API mais aussi au traitement fait par votre client web avant d’afficher la page finale.

En effet, le navigateur doit attendre le chargement et l’exécution complète de tous les scripts ainsi que les feuilles de style déclarées dans la balise <head> de votre document HTML.

Un navigateur n’est pas conçu pour charger un nombre illimité de ressources (images, vidéo, styles, scripts..), il les charge unitairement. Généralement, un browser effectue 8 requêtes HTTP simultanées par domaine.

Si vous êtes un développeur front-end, il est fortement recommandé de limiter les requêtes serveur et d’envoyer un code clean grâce à la concaténation et la compression de vos fichiers (JS , CSS et idéalement vos images et fichiers HTML) avant de les déployer en production. Ces tâches sont très répétitives et récurrentes, le temps passé dessus est quasi perdu et n’a pas de valeur ajoutée. Il faut donc idéalement automatiser ces actions.

Les 2 captures suivantes présentent la même page web sans puis avec les optimisations des requêtes serveurs grâce à la compression et la concaténation des fichiers. Il y a un gain de quelques centaines de millisecondes, ce qui est non négligeable.

Sélection_122

Sélection_128

 

Qu’est que Grunt ?

gruntjs

 

Grunt est un Task Runner, il permet de créer des tâches automatisées en JavaScript telles que les tâches de concaténation , de compression et de compilation des fichiers JS, SASS, CSS ainsi que plein d’autres tâches. Grunt possède d’ailleurs une multitude de plugins dans son éco-système dont le nom commence généralement par ‘grunt contrib*‘. Je vous invite à consulter la documentation complète pour plus d’information.

Prérequis

Avant tout, assurez vous d’avoir installer nodeJs (npm) car Grunt est un module développé sous NodeJs et donc s’installe avec le gestionnaire de package NPM

sudo apt-get update
sudo apt-get install nodejs
sudo apt-get install npm

Installer Grunt et ses modules

Maintenant installer Grunt via la commande suivante

sudo npm install -g grunt-cli

Une fois grunt est installé on peu commencer à utiliser ses plugins et les configurer pour cela il faut créer le fichier package.json et Gruntfile.js

Le fichier package.json devra être créé à la racine de votre projet. Il va servir à transformer votre dossier de travail en package NPM. Il contiendra la description ainsi que les dépendances de votre projet.

Le fichier package.json doit avoir la structure minimaliste suivante :

{
  "name": "ihm"
  "version": "1.0.0dev",
  "devDependencies": {
   "grunt": "~0.4.5",
  }
}

Ensuite créez votre package npm avec la commande suivante :

npm install

Un dossier node_modules sera créé, dans lequel sera regroupé tous les plugins node que l’on va installer par la suite.

Essayons de tester cela en installant le module de concaténation des fichiers JS : grunt-contrib-concat

npm install grunt-contrib-concat --save-dev

Vous allez remarquer qu’une ligne s’ajoute automatiquement à la liste des dépendances du fichier package.json, ceci grâce à l’option l’option –save-dev.

Si vous connaissez à l’avance la liste des plugins à installer,  vous pouvez automatiser l’installation de ces derniers avec un simple script bash. C’est pratique si vous travaillez à plusieurs sur une application web divisée en modules et que vous avez des tâches Grunt spécifiques par module par exemple. Voici un exemple de script :


#!/bin/bash
echo '1-accessing to ' $1
cd $1
echo '2- install npm and Grunt'
sudo apt-get update
sudo apt-get install nodejs
sudo apt-get install npm
install -g grunt-cli
echo '3- create package.json'
touch package.json
echo '{"name": "compressor","version": "1.0.0","devDependencies": {}}'&gt;package.json
npm install grunt-contrib-watch --save-dev
npm install grunt-contrib-cssmin --save-dev
npm install grunt-contrib-uglify --save-dev
npm install grunt-contrib-concat --save-dev
npm install grunt-ng-annotate --save-dev
echo '4- create gruntfile.js'
touch Gruntfile.js

Créer une tâche Grunt

Dans le fichier Gruntfile.js, on va configurer la tâche de concaténation des fichiers installé précédemment. Le code suivant détaille bien cette config :


module.exports = function(grunt) {
//charger le module installé grunt-contrib-concat
grunt.loadNpmTasks('grunt-contrib-concat');
// Configuration de Grunt
grunt.initConfig({
//concat: identifiant de plugin dans Grunt
concat: {
options: { //options supplémentaires
separator: ';', // permet d'ajouter un point-virgule entre chaque fichier concaténé.
},
//on peut séparer les tache par type de fichier
js: { //concaténer des fichiers JS
//liste des fichiers sources
src: ['js/lib/angular.min.js','js/controller/mainController.js',],
//fichier destination
dest: 'js/built_js/built.js'
}
//concaténer des fichiers css
css:{
src: ['css/bootstrap.min.css','css/loading-bar.css',],
dest: 'css/built.css', // la destination css finale
},
}
})
// Définition des tâches Grunt
grunt.registerTask('join', ['concat:js', 'concat:css']);
grunt.registerTask('concat_css', ['concat:css']);
grunt.registerTask('concat_js', ['concat:js']);
}

Pour lancer les tâches définies dans le code précédant revenez à votre terminal et tapez la commande grunt suivie du nom de la tâche que vous avez déclaré via la fonction grunt.registerTask():

grunt join
grunt concat_js
grunt concat_css

Plus de tâches Grunt

Compression JS: grunt-contrib-uglify

Ce plugin permet la compression des fichiers Javascript, il permet d’ailleurs de les concaténer si l’on passe en paramètres une liste des fichiers.
Pour garantir une compression sans erreur il vaudrait mieux compiler la syntaxe JS avec JSHINT (soit en l’intégrant dans votre éditeur ou de l’installer et l’exécuter en ligne de commande). On va donc enrechir notre Gruntfile comme suit :


module.exports = function(grunt) {
//charger le module installé grunt-contrib-concat
grunt.loadNpmTasks('grunt-contrib-concat');
//charger le module grunt-contrib-uglify
grunt.loadNpmTasks('grunt-contrib-uglify');
// Configuration de Grunt
grunt.initConfig({
//concat: identifiant de plugin dans Grunt
concat: {
options: { //options supplémentaires
separator: ';', // permet d'ajouter un point-virgule entre chaque fichier concaténé.
},
//on peut séparer les tâches par type de fichier
js: { //concaténer des fichiers JS
//liste des fichiers sources
src: ['js/lib/angular.min.js','js/controller/mainController.js'],//fichier destination
dest: 'js/built_js/built.js'
}
//concaténer des fichiers css
css:{
src: ['css/bootstrap.min.css','css/loading-bar.css',],
dest: 'css/built.css', // la destination css finale
},
}
//Minification JS
uglify: {
options: {}, //
js: {
src: ['js/built_js/built.js'], //on peut passer une liste des fichiers ils seront concaténés
dest: 'js/built_js/built.min.js'
}
}
})
// Définition des tâches Grunt
//tâches de concaténation
grunt.registerTask('join', ['concat:js', 'concat:css']);
grunt.registerTask('concat_css', ['concat:css']);
grunt.registerTask('concat_js', ['concat:js']);
//tâche de minification
grunt.registerTask('uglify_js', ['uglify:js']);
}

grunt-ng-annotate

Si vous utilisez le framework AngularJs comme language front-end, vous devez utiliser ce plugin pour préserver la notation de AngularJs après la compression. En effet, la compression permet de renommer toutes les variables le plus court possible (une seule lettre), et comme Angular possède des variables spécifiques comme le $scope, $http, $q et plein d’autres, il faut garder ces noms de variables même après la compression. Ce module permet permet également de concaténer plusieurs fichiers.

La syntaxe de ng-annotate est la suivante :


grunt.initConfig({
ngAnnotate: {
annotateController: {
files: {
'js/controller/ngAnnotatedMainController.js':['js/controller/MainController.js'],
},
},
})
//charger le module ngAnnnotate
grunt.loadNpmTasks('grunt-ng-annotate');
grunt.registerTask('ng_annotate', ['ngAnnotate:annotateController']);

grunt-contrib-cssmin

Ce plugin permet de compresser les fichiers css. La configuration est un petit peu différente des autres :


module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.initConfig({
//minifier le css
cssmin: {
options: {
shorthandCompacting: false,
roundingPrecision: -1
},
target: {
files: {
'css/main.min.css': ['css/main.css', bootstrap.css],
}
}
}
});
}

Pour cssmin on n’a pas besoin d’enregistrer la tâche avec grunt.registerTask() comme les autres, mais il suffit d’exécuter la commande suivante :

grunt cssmin

Et pour finir, une dernière tâche, pour moi la meilleure !
grunt-contrib-watch

Pour tout développeur/euse, compiler à chaque fois que vous faites des modifications sur vos fichiers devient vite répétitif et une perte de temps. Ce plugin est fait pour surveiller les fichiers que vous avez configuré dans le GruntFile.js et relance les tâches souhaitées.

//detecter les changement et relancer les taches en conséquences
watch: {
//observer les scripts
scripts: {
//liste des fichiers à observer
files: ['js/**/*.js', '!js/controller/built_js/*.js', 'Gruntfile.js'],
// tâche à exécuter au changement
tasks: ['ngAnnotate:', 'concat:js', 'uglify:js'],
},
//observer les styles
styles: {
files: 'css/**/*.css', // tous les fichiers css de n'importe quel dossier
tasks: ['cssmin']
},
options:{
reload: true
}
}

Pour lancer le watch :

grunt watch
Votre console va ressembler à cela :
Sélection_129

Conclusion
Grunt est un outil très puissant qui facilite la vie des développeurs, son eco-système est très riche grâce à ses différents modules. Je me suis focalisée sur quelques uns dans cet article, mais il en reste plusieurs tels que :

Développeuse Front-end, passionnée par le Javascript, j'essaye d'en apprendre davantage tout le jours, violoniste débutante.

Commentaires

  • Stéphane dit :

    Bon article et bien expliqué dans son ensemble 🙂

    Cependant, en 2016, Grunt, gulp, et même brunch sont obsolètes.
    L’article aurait eu plus de sens il y a 3 ans selon moi.

    • Billy dit :

      Article très clair et bien détaillé, merci à l’auteur.

      @Stéphane: Si ceux ci sont obsolètes, quels sont ceux qui aujourd’hui sont le plus en vogue ?

      • Stéphane dit :

        Hello,

        Aujourd’hui, j’utilise webpack. Il y en a d’autres du même genre, mais pour moi le plus complet est ce dernier. Brunch reste un très bon outils, mais il n’intègre pas NPM, contrairement à webpack.

    • Regis dit :

      @Stephane : J’ai toujours aimé l’extrême arrogance des devs fronts : “C’est comme ça qu’on fait !” ou encore “C’est Moderne parce que c’est cool ! ” ou bien l’inverse, je ne sais plus trop.

      Si je vous appelle les “Naude Jihesse”, c’est qu’il y a des raisons. Tro swag !

      Grunt, c’est bien, Gulp, c’est bien aussi, et WebPack c’est cool aussi.

      Un bon dev sait travailler en équipe et sait surtout quelles technos prendre pour que son équipe ne soit pas perturbée.

      Note : Pas la peine de répondre.

      • Stéphane dit :

        Mes précédents commentaires n’indique pas qu’il faut ABSOLUMENT utilisé Webpack et foutre Grunt (ou Gulp) à la poubelle.

        Grunt est un bonne outil, qui permet de faire énormément de chose. Mais cela n’empêche pas qu’il reste obsolètes par rapport aux outils qui sont plus récents et mieux structurés, avec de meilleurs perfs, etc.

        Donc avant de laisser un commentaire aussi naze, remplis de haine sur les devs fronts et de demander de ne pas répondre, essaye de comprendre.

      • Billy dit :

        @Regis: Tu es clairement hors propos … L’extrême arrogance que tu mentionnes n’était pas présente jusqu’à ce que tu arrives.

        @Stephane: J’en profite pour rebondir sur WebPack. Je ne connaissais pas avant ton poste et ça semble effectivement vraiment pas mal, je me pencherai peut-être dessus sur mes futurs projets histoire de varier les plaisirs avec Grunt qui nous sert au boulot.

  • Laisser un commentaire

    Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

    Nom*

    Email

    Website

    1 × deux =

    *

    Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

    En continuant à utiliser le site, vous acceptez l’utilisation des cookies. Plus d’informations

    Les paramètres des cookies sur ce site sont définis sur « accepter les cookies » pour vous offrir la meilleure expérience de navigation possible. Si vous continuez à utiliser ce site sans changer vos paramètres de cookies ou si vous cliquez sur "Accepter" ci-dessous, vous consentez à cela.

    Fermer