03. Initiation à grunt pour ameliorer son processus de développement

Nous avons vu précédemment une initiation à Gulp. Nous allons voir ici la même chose avec Grunt qui est son grand concurrent. Historiquement grunt est le plus ancien des deux outils mais son développement s’est arrêté pendant près de 2 ans avant d’être repris en 2016. Pendant ce temps, gulp est monté en puissance pour devenir aujourd’hui l’outil de choix. Néanmoins, grunt existe toujours et jouit d’un nombre de plugins très conséquents.

Préambule

Je vais essayer de me rapprocher au plus près de la leçon sur gulp, afin de pouvoir bien mettre en avant leur différence de fonctionnement.

Deux différences majeures sont à considérer : tout d'abord, la notation du fichier de configuration. Pour gulp c’est plus sous forme de fonction alors que pour grunt c’est plus sous forme d’objet. L’autre différence réside dans le fait que grunt récupère les fichiers source, applique le traitement et les écrit dans le répertoire de destination alors que gulp travaille en mémoire pour appliquer plusieurs actions d’un coup sans écrire de fichier.

Installation de Grunt

Grunt et un outil qui fonctionne avec NPM, pour ceux qui ne connaissent pas l'outil, je vous conseille donc de regarder la leçon sur les bases de NPM. Nous repartirons d’ailleurs de ce projet pour travailler avec Grunt.

Grunt est un outil NPM en ligne de commande qui peut s’installer de manière globale ou locale. Afin de simplifier le travail en équipe et d’éviter toute incompatibilité entre les projets, j’ai pris l’habitude de l’utiliser en local.

Reprenons donc notre projet initié avec NPM qui contient seulement un fichier index.html et 2 dépendances pour y installer Grunt. Suite à la reprise de grunt en 2016, il est passé de la version 0.4.5 à la version 1.x.x, ce qui pose quelques problèmes de dépendance de plugins. Etant donné que ce changement est récent, je vais, afin d'éviter tout problème, installer la version précedente, 0.x.x

$> npm install grunt@0.*.* –save-dev

Comme nous travaillons en mode local, nous allons l’ajouter dans la section script du package.json, ce qui donne :

{
  "name": "mon-nouveau-projet",
  "version": "1.0.0",
  "description": "Un nouveau projet pour tester NPM",
  "main": "index.html",
  "scripts": {
    "server": "lite-server",
    "grunt": "grunt",
    "start": "npm run server"
  },
  "dependencies": {
    "bootstrap": "^3.3.7",
    "jquery": "^3.1.1"
  },
  "devDependencies": {
    "grunt": "^0.4.5",
    "lite-server": "^2.2.2"
  }
}

Ensuite, pour fonctionner Grunt à besoin d’un fichier de configuration qui sera utilisé pour décrire les tâches à réaliser. Ce fichier s’appelle Gruntfile.js et est placé à la racine du projet.

Ce fichier contiendra les paramètres de nos tâches ainsi que leur ordonnancement.

Plugins

Comme gulp, grunt à besoin pour fonctionner de plugin qu'il faut au préalable installer.

Concaténation de CSS

Pour ce premier test, nous allons concaténer des fichiers CSS en un seul. Pour cela, nous créons dans un premier temps, un répertoire css et y plaçons au moins deux fichiers CSS. Puis nous installons le plugin permettant de concaténer des CSS grunt-contrib-concat.

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

Les plugins commençant par grunt-contrib sont les plugins officiels de grunt

Nous allons placer le résultat dans un répertoire build grâce à la tâche concat:buid comme configuré ci-dessous:

module.exports = function (grunt) {

    grunt.loadNpmTasks('grunt-contrib-concat'); // chargement du plugin 'grunt-contrib-concat'

    grunt.initConfig({
        concat: { // paramètre du plugin 'grunt-contrib-concat'
            options: { 
                // option globale à toutes les tâches utilisant ce plugin
            },
            build: { // une tâche utilisant ce plugin avec ses options spécifiques
                src: ['css/*.css'], // fichier source à concaténer
                dest: 'build/app.css', // fichier de destination du résultat
            },
            autre : { // une autre tâche utilisant ce plugin avec ses options spécifiques

            }
        },
    });

    // définition de notre tâche par défault qui appelle notre tâche de concaténation
    grunt.registerTask('default', ['concat:build']);

};

L'utilisation est toujours la même. Tout d’abord, on charge les plugins avec loadNpmTasks, puis la méthode initConfig permet de configurer chaque plugin. C’est un objet qui contient une propriété pour chaque plugin. Chacun contient autant de sous propriétés que de tâches à configurer (ici build et autre).

Ensuite registerTask permet d’enregistrer nos tâches, afin que celles-ci soit appelées dans l’ordre souhaité.

Minification de CSS

Nous allons ajouter une deuxième tâche qui, après la concaténation, effectura la minification de notre css. Pour cela, nous installons le plugin grunt-contrib-cssmin

$> npm install --save-dev grunt-contrib-cssmin

Ce qui donne dans nore fichier de configuration:

module.exports = function (grunt) {

    grunt.loadNpmTasks('grunt-contrib-concat'); // chargement du plugin 'grunt-contrib-concat'
    grunt.loadNpmTasks('grunt-contrib-cssmin'); // chargement du plugin 'grunt-contrib-cssmin'

    grunt.initConfig({
        concat: { // paramètre du plugin 'grunt-contrib-concat'
            options: {
                // option globale à toutes les tâches utilisant ce plugin
            },
            build: { // une tâche nommée 'build' utilisant ce plugin avec ses options spécifiques
                src: ['css/*.css'], // fichier source à concaténer
                dest: 'build/app.css', // fichier de destination du résultat
            },
            autre: { // une autre tâche nommée 'autre' utilisant ce plugin avec ses options spécifiques

            }
        },
        cssmin: {
            build: { // une tâche nommée 'build' utilisant ce plugin avec ses options spécifiques
                files: {
                    'build/app.min.css': ['build/app.css'] // fichier de sortie : fichiers d'entrées
                }
            }
        }
    });

    // définition de notre tâche de concaténation
    grunt.registerTask('css:concat', ['concat:build']);

    // définition de notre tâche par défaut qui appelle notre tâche de concaténation et de minification
    grunt.registerTask('default', ['css:concat', 'cssmin:build']);

};

Après exécution de grunt, vous devriez avoir dans votre répertoire build un fichier app.css qui contient les fichiers CSS concaténés et un fichier app.min.css qui est la version minimifiée.

Conclusion

Comme nous l'avons vu, grunt produit pour l'utilisateur final, à peu près la même chose que gulp. La différence majeure réside dans la syntaxe de configuration. Personnellement, je préfère gulp car je trouve qu’il est beaucoup plus simple d’exécuter plusieurs actions sur un même fichier et de l'agrémenter de JavaScript personnalisés.