GruntJS, le script d’automatisation pour le web

Une des bonnes pratiques web consiste à minifier tous les scripts JavaScript et CSS puis à les concaténer afin de ne servir que deux fichiers lorsque le site est en production. Ce a des fins de performances.

Il existe déjà des outils le permettant, tels que Capistrano, Ant, ou le traditionnel script Bash. Depuis début 2012 on entend parler de GruntJS, plus encore ces derniers mois.

GruntJS reprend le même principe qu’Ant, à savoir exécuter des tâches définies par l’utilisateur. Il est basé sur NodeJS et est actuellement disponible en 0.3.9.

L’article qui suit est un tutorial expliquant pas à pas comment installer et configurer GruntJS pour minifier et concaténer les fichiers JavaScript et CSS.

Installer GruntJS

Pour utiliser GruntJS il faut au préalable avoir installé NodeJS.

La version de GruntJS que nous allons installer est la 0.4.0rc7. Celle-ci offre de nombreuses améliorations par rapport à la 0.3.9, notamment dans le pattern matching des fichiers.

Comme la documentation l’indique il est préférable d’installer grunt localement (NodeJS permet d’installer les modules dans le répertoire courant de votre projet ou globalement, dans votre système de fichiers afin d’y avoir accès partout) :

npm install grunt@0.4.0rc7

Le client en ligne de commandes lui, doit à l’inverse être installé globalement :

npm install grunt-cli@latest -g

Une fois ces deux modules NodeJS installés (grunt-init ne nous servira à rien) il faut maintenant installer les tâches dont nous allons nous servir :

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

L’option –save-dev ajoute la dépendance dans package.json qui est abordé un peu plus bas.

Les tâches sont disponibles sur le site officielles ainsi que sur Github.

Minifier et concaténer les fichiers JavaScript et CSS

Le seul fichier nécessaire pour configurer grunt est « Gruntfile.js » (« grunt.js » dans la 0.3.9). Cependant nous allons également créer un fichier nommé « package.json » qui permettra à NodeJS d’installer en une commande toutes les dépendances nécessaires.

package.json :

{
  "name": "project_name",
  "version": "0.1"
}

Les modules installés précédemment avec l’option –save-dev viennent s’ajouter dans ce fichier.

gruntfile.js :

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    clean: {
      src: [
        'static/css/sitename.min.css',
        'static/js/sitename.js',
        'static/js/sitename.min.js'
      ]
    },
    mincss: {
      compress: {
        files: {
          'static/css/sitename.min.css': [
            'static/css/reset.css', 
            'static/css/core.css', 
            'static/css/site.css'
          ]
        }
      }
    },
    concat: {
      dist: {
        src: [
          'static/js/jquery.min.js', 
          'static/js/*.js',
          '!static/js/modernizr*.js'          
        ],
        dest: 'static/js/sitename.js'
      }
    },
    uglify: {
      dist: {
        src: '<%= concat.dist.dest %>',
        dest: 'static/js/sitename.min.js'
      }
    }
  });

  // Defining a custom task to delete previously generated file before generate them
  grunt.registerTask('clean', 'Clean the previously generated files', function() {
    var files = grunt.config('clean').src;

    for (var i = 0; i < files.length; i++) {
      grunt.file.delete(files[i]);
    }
  });

  // loading the required tasks
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-mincss');

  grunt.registerTask('default', ['clean', 'mincss', 'concat', 'uglify']);
};

grunt.initConfig() contient les paramètres de configurations des différentes tâches.

La tâche « clean » est une tâche que j’ai défini moi même en fin de fichier. Elle supprime les différents fichiers définis dans sa configuration. Utile pour supprimer les fichiers précédemment concaténés et minifiés, sinon grunt ne les vide pas mais écrit à la suite.

mincss concatène et minifie les fichiers CSS.

Concat fait de même pour le JavaScript mais la sélection de ceux-ci est un peu délicate, l’ordre d’inclusion de ceux-ci étant important. Ici jQuery est spécifié avant la règle allant chercher tous les .js du dossier. De cette façon jQuery sera inclus en premier.
Le point d’exclamation avant le chemin vers modernizr l’exclu de la liste (il faut toujours inclure modernizr en début de page, tandis que le script généré sera inclus en bas de page). Il est important de mettre les fichiers exclus en fin de liste sinon la règle plus générale « static/js/*.js » l’emportera.
Cette pattern de sélection peut-être utilisée avec n’importe quelle tâche.

Uglify est la tâche minifiant le JavaScript.

Après la définition de la tâche « clean » se trouve le chargement des tâches listées via la méthode grunt.loadNpmTasks(). Il faut se rappeler d’installer les modules correspondants afin de les utiliser.

La dernière ligne utilise elle aussi la méthode registerTask() mais cette fois-ci avec deux paramètres : le nom de la tâche et un array contenant la liste des tâches à exécuter.
Il est important de nommer cette tâche « default » afin que grunt l’exécute sans avoir besoin de paramètres supplémentaires.

Pour finir, il nous reste à exécuter notre fichier. A la racine du projet taper :

grunt
(grunt.cmd sous windows)

Du vert devrait apparaître dans le terminal indiquant la bonne réussite de la tâche. Si une erreur se produit les messages sont suffisamment explicites pour pouvoir la résoudre rapidement.

Avec Grunt il est tout à fait possible d’aller plus loin en utilisant par exemple des variables afin d’éviter de retaper les chemins, de modifier du HTML, etc. Cet article étant juste une introduction en la matière.

Commentaires

  1. Sylvain

    Pas de commentaire sur ton tutoriel, dommage, caril est simple et parfaitement compréhensible :)

    Merci

  2. Antoine Descamps

    Merci :)

  3. Etienne

    Bonjour,
    Je suis nouveau dans le monde de nodejs et crunt. Je suis tombé sur ton tuto mais je ne comprends pas tout. Par exemple, tu donnes le code du fichier gruntfile.js. Mais il y a déjà un fichier nommé comme ca dans le dossier /grunt. Il faut remplacer celui-la par ton code ? Ou alors il faut mettre gruntfile.js ailleur ?

Ajouter un commentaire