Gulp est un nouveau venu dans le monde nodejs, et se veut être un outil de build moderne et puissant, visant à détrôner grunt de sa mainmise sur le monde du build.
Mais tout d’abord, qu’est ce qu’un outil de build ? C’est un programme destiné à l’organisation et l’exécution des tâches composant un build, par exemple la compilation ou le packaging de fichiers sources. Dans le monde java, on pourra citer gradle, maven ou ant par exemple. Dans le monde JavaScript, le leader actuel est grunt. On pourra citer quelques exemples de tâches de build comme la minification de fichiers, la concaténation de fichiers, ou encore la compilation de CoffeeScript vers JavaScript.
Grunt étant déjà bien implanté, qu’est ce que gulp apporte de plus pour que l’on parle autant de lui ? C’est ce que nous allons voir ci-dessous.
Concepts fondamentaux
Gulp se veut plus idiomatique du monde nodejs que ses concurrents en s’appuyant non pas sur une syntaxe déclarative (par configuration), mais sur une approche programmatique. Le gulpfile, fichier de base de l’outil, n’est rien de plus qu’un script nodejs.
Gulp profite de cet avantage pour s’appuyer fortement sur les fonctionnalités de streaming fournies par nodejs. Pour expliquer ce que cela apporte, prenons un exemple : imaginons que notre projet contient plusieurs fichiers JavaScript et que nous souhaitons optimiser leur intégration dans les navigateurs. Pour cela nous allons les minifier puis les concaténer en un seul fichier. L’approche classique proposée par les autres outils de build est d’écrire des fichiers temporaires entre chaque étape avant d’avoir la version finale :
Gulp choisit de tout passer par un flux continu, qui permet d’éviter l’écriture de fichiers temporaires :
Les avantages de cette approche sont doubles :
- le traitement de fichiers est beaucoup plus rapide. Sur des builds relativement standards (minification, concaténation de fichiers js et css), les temps de builds se retrouvent divisés par 2 à 3 par rapport à grunt ;
- la lisibilité est globalement améliorée car il y a moins d’étapes intermédiaires inutiles.
Toujours dans cet objectif de lisibilité, la philosophie sous tendant gulp est « un plugin = une action ». Ici, le plugin less ne fait pas de minification ou de concaténation par exemple. Cette philosophie mène à des plugins très simples, souvent composés d’une seule fonction d’une trentaine de ligne.
Enfin, une des grandes forces de gulp réside dans son API, composée d’une poignée de fonctions simples.
Gulp tournant autour de l’idée que tous les traitements de fichiers doivent se faire dans un flux, il fournit un moyen de lire les fichiers via gulp.src
, d’appliquer des modifications à ce flux via la méthode pipe
et enfin d’écrire la sortie du flux sous forme de fichier via gulp.dest
. L’ensemble de ces fonctionnalités sont accessibles depuis la ligne de commande gulp si elles sont déclarées sous forme de tâches, avec gulp.task.
Enfin, gulp.watch
permet de relancer automatiquement les tâches concernées par certains fichiers dès que ceux-ci sont modifiés.
L’avantage de gulp étant des fichiers de build très lisibles, un exemple est sans doute bien plus parlant :
// Ci-dessous, contenu du fichier gulpfile.js var coffee = require('gulp-coffee'); var concat = require('gulp-concat'); var uglify = require('gulp-uglify'); var imagemin = require('gulp-imagemin'); var paths = { scripts: ['client/js/**/*.coffee'], images: 'client/img/**/*' }; // Compilation du coffeescript, minification et concaténation gulp.task('coffee', function() { return gulp.src(paths.scripts) .pipe(coffee()) .pipe(uglify()) .pipe(concat('all.min.js')) .pipe(gulp.dest('build/js')); }); // Copie des images statiques avec optimisation gulp.task('images', function() { return gulp.src(paths.images) .pipe(imagemin({optimizationLevel: 5})) .pipe(gulp.dest('build/img')); }); // Relance les tâches ci-dessus lorsque les fichiers changent gulp.task('watch', function () { gulp.watch(paths.scripts, ['coffee']); gulp.watch(paths.images, ['images']); }); // La tâche par défaut, qui est appelée lorsqu'on lance `gulp` depuis la ligne de commande gulp.task('default', ['coffee', 'images', 'watch']);
Faut-il migrer vers gulp ?
Mais avec tout ça, on voit maintenant ce qu’est gulp et ce qu’il fournit, mais faut-il quitter son outil de build pour tout migrer vers gulp ?
Il faut sans doute nuancer ce qu’apporte gulp : l’outil est encore jeune, et la communauté bien que très vivante, n’est pas encore extrêmement étendue. Grunt est pour l’instant très bien implanté et on trouve facilement les réponses aux questions que l’on pourrait se poser. On pourra cependant constater que la grande majorité des plugins existant pour grunt existe déjà pour gulp.
Quant au gain de performance, même s’il est réel, il est rarement un problème avec grunt, qui par ailleurs implémentera probablement un moyen de faire du streaming dans sa prochaine version majeure.
Signe des temps, le projet yeoman, le célèbre générateur de code, se voit déjà proposer des pull requests concernant l’intégration de gulp en lieu et place de grunt.
En conclusion, sur un projet existant déjà équipé de grunt, il n’est probablement pas nécessaire de dépenser son énergie à migrer vers gulp. Par contre, sur un nouveau projet, il peut être pertinent de parier sur gulp, car la communauté JavaScript porte aux nues ce projet, visiblement promis à un très bel avenir.