Introduction à Gulp

MoOx
MoOx 2014/04/29

Vous commencez tous à connaitre les tasks runners, ces outils qui permettent d'automatiser les tâches de développement récurrentes. Personnellement je n'ai pas arrêté d'en parler depuis que Grunt à déterré cette vielle problématique, assez récente pour le développement Web côté front end.

Il faut avouer que de par l'évolution du développement Web, côté front end, on voit beaucoup de personnes qui n'ont pas de vraies bases de développeur. Je veux dire par là non pas que ces personnes sont incompétentes, mais plutôt qu'il manque parfois la bonne flemme du développeur, celle qui le pousse à développer des solutions techniques pour mieux développer des produits. Il manque un peu d'algorithmie dans les veines, de curiosité et d'amour du risque. Ce n'est pas en restant dans sa zone de confort qu'on va de l'avant. Enfin si vous avez des exemples contraires, je suis preneur. Mais tout cela doit provenir du fait que pas mal de métiers dans le web sont nouveaux, dont celui de « développeur Web front end » et que du coup, peu de personnes ont initialement suivi des formations appropriés (pour ma part je proviens d'une formation d'analyste-programmeur, conception et développement software quoi). Je remarque que niveau back end il y a beaucoup moins de lacunes, du fait que les problématiques gérées de ce côté sont (il me semble) moins nouvelles.

Bref. Je ne vais pas m'éterniser sur une intro du pourquoi on met en place un task runner, ni faire une comparaison entre Make, Rake, Cake, Jake, Grunt, Brunch et Broccoli. Rentrons dans le vif. Parlons Gulp.

Pourquoi Gulp

Je vais faire court. Pour faire simple, son point fort réside dans le fait qu'il utilise des streams (tl;dr: un flux de données - en mémoire) et qu'il limite au maximum l'utilisation de fichiers. Au point qu'il existe une police Gulp pour vous dire. Si vous voulez en savoir plus sur les streams, n'hésitez pas à lire l'article de Nicolas Froidure Gulp remplacera-t-il Grunt ? qui contient une partie explicative sur les streams.

Dans la pratique cela évite d'avoir un gruntfile qui, si on imagine une task sass -> autoprefixer -> csso, passe 3 fois par des lectures/écritures sur le système de fichiers.

Sans stream

Et du coup au lieu d'avoir un fichier de conf d'une soixantaine de lignes, on arrive à avoir quelque chose de concis (une vingtaine de ligne seulement).

Avec stream

Installation

Pour avoir la commande globale sur le système (comme grunt-cli) :

$ npm i -g gulp

Ensuite dans votre projet :

$ npm i -D gulp gulp-util gulp-plumber gulp-WHATEVER

Note : npm i -D == npm install --save-dev, c'est cadeau.

Bon dans mon exemple j'ai mis un peu n'importe quoi, donc on va faire un mini workflow de hipster hacker.

Utilisation

On part avec une tâche très simple : transpiler cssnext.

$ mkdir putaindegulp && cd putaindegulp
$ npm init
$ npm i -D gulp gulp-util gulp-plumber gulp-cssnext gulp-csso minimist
var gulp = require("gulp");
var gutil = require("gulp-util");
var plumber = require("gulp-plumber");
var cssnext = require("gulp-cssnext");
var csso = require("gulp-csso");
var options = require("minimist")(process.argv.slice(2));

gulp.task("styles", function() {
  gulp
    .src("./src/css/*.css")
    .pipe(!options.production ? plumber() : gutil.noop())
    .pipe(cssnext({ sourcemap: !options.production }))
    .pipe(options.production ? csso() : gutil.noop())
    .pipe(gulp.dest("./dist/css/"));
});

gulp.task("default", ["styles"], function() {
  gulp.watch("./src/css/**/*", ["styles"]);
});

Voilà c'est tout. Et heureusement.

Bon, on se refait l'exemple commenté :

// bah là ok, on est obligé d'y passer pour avoir l'API Gulp
var gulp = require("gulp");

// Ça c'est optionnel, c'est pour avoir (entre autres la méthode noop())
// je reviens dessus après
// https://github.com/gulpjs/gulp-util
var gutil = require("gulp-util");

// Là on a Mario le plombier qui fixe la tuyauterie foireuse.
// Ce plugin patch le problème de stream avec node.js qui fait que tout le process
// explose à la moindre erreur (pas pratique en cas de watch par exemple)
// en gros, il remplace la méthode pipe et attrape les erreurs pour les ressortir gentiment
// https://gist.github.com/floatdrop/8269868
var plumber = require("gulp-plumber");

// Ici, rien de magique, du plugin en veux-tu en voilà
var cssnext = require("gulp-cssnext");
var csso = require("gulp-csso");

// ici on chope les options de la ligne de commande
// exemple: pour avoir options.production à true,
// il suffit de faire `gulp --production`
var options = require("minimist")(process.argv.slice(2));

// Définition d'une tâche, un nom et une fonction.
// Ce qui est pratique c'est le fait de pouvoir mettre ce qu'on veut
// y compris un console.log() ^^
// un autre paramètre peut être ajouté avant la fonction, qui permet de préciser
// les dépendances (cf task dev plus bas par exemple)
gulp.task("styles", function() {
  // Ici on attrape les fichiers (glob classique)
  // à la racine (on va considérer que nos fichiers finaux ne seront pas dans
  // des sous dossiers, réservés aux partials & co)
  gulp
    .src("./src/css/*.css")

    // On utilise plumber que si on build en dev, sinon faut que ça pête, qu'on
    // soit prévenu lors d'un build pour la prod
    .pipe(!options.production ? plumber() : gutil.noop())

    // Et là on pipe nos plugins
    // toujours en jouant avec les options si besoin
    .pipe(
      cssnext({
        compress: options.production,
        sourcemap: !options.production,
      }),
    )

    // Super important, on convertit nos streams en fichiers
    .pipe(gulp.dest("./dist/css/"));
});

// Ici on a une tâche de dev qui lance un watch APRES avoir exécuté `styles` une fois
gulp.task("default", ["styles"], function() {
  // gulp.watch est natif (pas comme avec grunt)
  // vous noterez qu'ici par exemple on va surveiller tous les fichiers
  // et non pas ceux juste à la racine par exemple
  gulp.watch("./src/css/**/*", ["styles"]);
});

// Comme grunt, `gulp` sans argument lancera la tâche `default`.

Bien entendu, vous avez déjà compris que si vous voulez remplacer cssnext par Sass, c'est l'histoire de 4 secondes.

Chez Putain de code ! on a aimé Gulp. Il faut bien avouer que ça va vite (encore plus appréciable lorsque l'on n'a pas de SSD) et que c'est plaisant à écrire comparé à Grunt. Pas de configurations pas spécialement verbeuse et trop espacée. Avec Gulp on se sent plus libre, moins contraint. Du coup, on avait carrément refait notre site avec Gulp (puis au passage un petit refresh graphique tant qu'à faire).

Mise à jour: depuis nous avons encore simplifié notre process et nous nous sommes passé de Gulp.

Pour aller plus loin, vous n'avez qu'à ouvrir notre ancien Gulpfile et regarder nos tasks de l'époque qui vont de la plus simple à la plus compliqué.

Pour voir des tâches plus « real world example » je vous invite à regarder les tasks suivantes :

  • server, le server de dev local avec livereload dedans ;
  • watch, le classique et si simple watcher ;
  • deploy, la tâche pour publier le dossier dist/ sur les gh-pages ;
  • icons, qui transforme des SVG en fontes d'icones avec le bout de CSS qui va bien ;
  • scripts-linting, qui vérifie la qualité du code ;
  • scripts, du browserify pour nos JS côté client ;
  • stylesheets, notre tâche pour coder des css du futur ;

Vous reprendrez bien un peu de… Gulp* ! Pardon.

Si vous avez encore envie de détails je vous renvoie sur l'article anglais Getting started with gulp qui détaille tellement bien chaque point que même un anglophobe comprendrait.

Vous avez aussi une documentation très bien faite, qui comporte carrément des exemples officiels tout prêts.

Comme je vous disais plus tôt, les auteurs de Gulp sont assez carrés et valident (ou plutôt invalident) les plugins qui ne respectent pas les règles. Je trouve que c'est gage de qualité.

Pour finir quelques liens pour ceux qui en veulent toujours plus :

$ gulp bisous
❯ ♡ 😘
Vous avez aimé cet article?
Le partager sur Twitter
← Articles
Ne rien rater
Sur les réseaux
Twitter
Facebook
Facebook
Apple Podcast
Soundcloud
Sur le chat
Discord