keyboard_arrow_up

Organiser ses tâches Gulp

Rédigé par Sylvain Lavielle
Développeur web freelance expert Drupal sur Toulouse

Le 01/10/2019

Gulp est un outil basé sur node.js qui fait partie de la famille des tasks runners. Il est utilisé pour effectuer des tâches sur les assets front-end d'une application ou d'un site web de façon à transformer les assets sources en quelque chose d'utilisable ou de plus optimisé pour un navigateur web.

Voici en général le type de tâches exécutées par Gulp :

  • Transpilation du SASS en CSS
  • Aggrégation et optimisation des scripts JS
  • Aggrégation de fichiers SVG dans un fichier de sprite SVG
  • etc.

Le principe de Gulp est assez simple et bien décrit dans un grand nombre d'articles sur le web. On définit des tâches dans un fichier principal nommé gulpfile.js, chaque tâche est une suite de transformations réalisées par des plugins Gulp sur des assets spécifiques. Un des problèmes avec Gulp, c'est que l'ensemble des tâches et des plugins utilisés pour chaque tâche peut vite devenir conséquent. Le fichier gulpfile.js peut alors vite devenir un vilain plat de spaghetti si l'ensemble des tâches y sont implémentées directement.

Il est donc nécessaire de trouver une solution pour rendre l'ensemble de notre process Gulp plus lisible et plus maintenable.

Que suggère la documentation Gulp ?

La documentation Gulp fait d'ailleurs référence à ce problème et donne une solution élégante pour mieux organiser les tâches :

Au lieu d'utiliser directement un fichier gulpfile.js, on crée un répertoire gulpfile.js contenant un fichier index.js. Le fichier index.js se comporte alors comme un fichier gulpfile.js, mais on peut en plus utiliser le répertoire gulpfile.js pour implémenter séparément chaque tâche et utiliser require pour les inclure dans le fichier index.js principal.

Une petite touche personnelle

Personnellement, j'aime bien regrouper l'ensemble des tâches dans un sous-répertoire gulpfile.js/tasks.

J'ajoute un fichier gulpfile.js/conf.js. destiné à accueillir la configuration de l'ensemble des tâches. Cela permet de ne pas avoir de valeurs littérales (comme les chemins) dans les tâches, ce qui facilite donc leur réutilisation.

Voici par exemple à quoi ressemble la topologie de mon répertoire gulpfile.js :

  • gulpfile.js
    • tasks
      • clean.js
      • fonts.js
      • scripts.js
      • styles.js
      • ...
    • conf.js
    • index.js

Le fichier index.js

Voici maintenant à quoi ressemble le fichier index.js

gulpfile.js/index.js

var gulp = require("gulp");

// Single tasks
gulp.task("scripts", require("./tasks/scripts"));
gulp.task("styles", require("./tasks/styles"));
gulp.task("clean", require("./tasks/clean"));
gulp.task("svg", require("./tasks/svg-sprite"));
gulp.task("fonts", require("./tasks/fonts"));
gulp.task("image", require("./tasks/img-opti"));

// Meta tasks
gulp.task("build", gulp.parallel("styles", "scripts", "svg", "fonts","image"));

// Default tasks
gulp.task("default", gulp.series("clean","build"));

// Dev tasks
gulp.task("w", gulp.series('default', require("./tasks/watch")));
gulp.task("watch", gulp.series('default', require("./tasks/watch")));

Chaque tâche "finale" est incluse par un require et l'ensemble du processus reste très lisible.

Les fichiers de tâches

Prenons par exemple la tâche scripts.js. Voici à quoi ce fichier va ressembler :

gulpfile.js/tasks/scripts.js

var argv = require('minimist')(process.argv.slice(2)),
    gulp = require("gulp"),
    util = require("gulp-util"),
    conf = require('../conf'),
    onError = require('./helpers/onError'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    sourcemaps = require('gulp-sourcemaps');

var production = argv.production;

module.exports = function () {
  return gulp.src(conf.tasks.scripts.paths.src)
  .pipe(onError())
  .pipe(!production ? sourcemaps.init() : util.noop())
  .pipe(!production ? util.noop() : uglify())
  .pipe(!production ? sourcemaps.write() : util.noop())
  .pipe(concat(conf.tasks.scripts.paths.dist.file))
  .pipe(gulp.dest(conf.tasks.scripts.paths.dist.path));
};

Là encore ça reste très lisible et compréhensible (pour peu qu'on connaisse la syntaxe Gulp quand même). L'ensemble des paramètres de configuration utilisés provient du fichier de configuration gulpfile.js/conf.js  (variable conf)

Le fichier de configuration des tâches

Ce fichier est organisé en tâches de façon à bien cloisonner la configuration de chaque tâche indépendamment des autres et ainsi rendre l'ensemble plus facile à lire et à reconditionner pour un autre projet :

gulpfile.js/conf.js

module.exports = {
  tasks: {

    // Conf for the scripts task 
    scripts: { 
      paths: {
        src: [
          './assets/scripts/*.js',
          'node_modules/bootstrap/dist/js/bootstrap.js'
        ],
        dist:{
          path: './dist/scripts/',
          file: 'scripts.js'
        }
      }
    }

    // Conf for other tasks here 
  }
};

Sujets abordés dans cet article