Niveau Niveau confirmé

Introduction à Gulp

Tutorieldéveloppement

Publié par le , mis à jour le (177738 lectures)

css javascript sass less workflow gulp nodejs

Gulp est un "Automatiseur de tâches", un task runner comme disent nos amis anglophones, c'est à dire qu'il est capable de lancer des bouts de scripts à votre place tout seul comme un grand.

Ces tâches dépendent de votre bon vouloir et peuvent être très variées :

  • des opérations simples telles que minifier ou concaténer du CSS ou du JavaScript,
  • la création ou la suppression de dossiers ou de fichiers (possibilité de créer un projet à partir de zéro),
  • l'optimisation, la compression d'images,
  • la création de serveur local permettant de tester sur de multiples périphériques en même temps,
  • la simulation de navigateurs fantômes conçus pour parcourir et tester les regressions d'affichage d'une page,
  • etc.

gulp

T'as une tâche là !

Pour vous représenter le nombre d'actions réalisables par Gulp, sachez que les quelques 2000 plugins recensés représentent tout autant de tâches exécutables au sein de votre projet.

En clair, intégré à votre environnement de travail, Gulp va vous permettre d'économiser énormément de temps en se chargeant de toutes les tâches répétitives et automatisables. Vous n'aurez plus qu'à vous concentrer sur votre vrai travail : produire du code propre et fonctionnel, et prendre un café de temps en temps.

Les pré-requis de Gulp

Pour accomplir vos premiers exploits avec Gulp, vous n'aurez besoin que de :

  • node.js
  • ne pas être trop allergique à la ligne de commande

Node.js

Node.js est un environnement JavaScript qui compte parmi les projets de Linux et qui est doté d'un vaste écosystème de plugins nommé "npm".

Avant de pouvoir exécuter Gulp, vous allez devoir installer Node.js sur votre machine.

nodeJS

Ligne de commande

Les outils tels que Node.js, nmp ou gulp ont été conçus pour être exécutés en ligne de commande, c'est à dire dans une fenêtre d'instructions très rudimentaire sans aucune couche graphique superficielle.

Cela risque de vous picoter au début, si comme moi vous préférez les interfaces graphiques évoluées, mais vous allez vous habituer rapidement. D'autant plus que vous ne lancerez votre terminal de commande qu'une fois dans la matinée, juste au moment d'aller à la machine à café.

À ce sujet, n'hésitez pas à parcourir l'article Bower pour les nuls (comme moi) qui aborde les rudiments de la ligne de commande et les bonnes pratiques pour débuter avec elle.

Installer Gulp

Dès que Node.js est installé, ouvrez un terminal de commande n'importe où, et tapez:

npm install gulp -g

Attention, ce tutoriel a initialement été rédigé en 2015 et est basé sur Gulp version 3. il se peut que vous ayiez à adapter certaines portions de code si votre version de Gulp est plus récente.

Cette instruction aura pour effet d'installer Gulp de manière globale sur votre ordinateur, et une fois pour toutes.

Remarque : si vous êtes sur Mac ou Linux, vous aurez sans doute besoin de faire précéder cette syntaxe d'un sudo afin de disposer des droits suffisants, ce qui donnera:  
sudo npm install gulp -g

terminal

Gulp à présent installé, il lui faudra une combinaison de deux fichiers à la racine d'un projet pour être totalement fonctionnel :

  • package.json : contient la liste des plugins gulp (ou autres) nécessaires à vos tâches
  • gulpfile.js : contient la liste des tâches à réaliser

Voyons à présent comment créer et alimenter ces deux fichiers essentiels de notre projet de test.

Gulp en action dans un projet !

Pour se mettre directement dans le bain, rien de mieux qu'un projet concret.

Notre objectif est d'automatiser l'ensemble des tâches CSS au sein du projet : la compilation de LESS (ou Sass) vers CSS, l'ajout de préfixes CSS3, la minification du fichier CSS, et son renommage en ".min.css", par exemple.
Le but étant que toutes ces actions se mettent en branle automatiquement dès lors que nous enregistrons nos modifications CSS. Oui, rien que ça.

Structure du projet

Notre projet sera constitué ainsi :

  • src : dossier de travail, où sont contenus les fichiers .less de développement
  • dist : dossier de production, où seront créés les fichiers produits par Gulp (ce dossier sera généré, il n'est pas utile qu'il soit présent au départ du projet)

Visuellement, cela pourrait ressembler à cette structure assez classique, à savoir que notre feuille de styles .less sera contenue dans le dossier src/assets/css

structure

Initialisation du projet

Pour rappel, deux fichiers sont essentiels à l'exécution de vos tâches Gulp, il s'agit de package.json et gulpfile.js. Ils doivent se trouver à la racine de votre projet.

Le fichier package.json

Il est possible de créer un fichier package.json vierge à partir de zéro, à l'aide de l'instruction suivante (placez votre terminal de commande dans votre dossier de projet) :

npm init

npm vous demandera alors plein d'informations (nom du projet, licence, etc.), le plus simple est généralement de valider point par point en confirmant avec la touche Entrée.

L'étape suivante est alors de déclarer et d'installer un par un chaque plugin qui sera nécessaire pour votre projet, en commençant par exemple par Gulp lui-même :

npm install gulp --save-dev

... et ainsi de suite pour chaque plugin.

Sinon, une manière plus simple est tout simplement de récupérer un package.json existant et de copier-coller son contenu au sein du votre, et de lancer l'instruction suivante pour tout installer dans votre dossier de projet :

npm install

Pour info, npm install a pour mission d'installer tous les plugins listés dans le fichier package.json

Au final, notre fichier package.json minimal et fonctionnel pour notre projet pourra contenir les instructions suivantes :

{
  "name": "projet",
  "version": "0.0.1",
  "devDependencies": {
    "gulp": "latest",
    "gulp-load-plugins": "latest",
    "gulp-rename": "latest",
    "gulp-csso": "latest",
    "gulp-less": "latest",
    "gulp-csscomb": "latest",
    "gulp-cssbeautify": "latest",
    "gulp-autoprefixer": "latest"
  }
}

Et l'ensemble des plugins devra être installé dans un dossier node_modules que npm install aura généré :

node modules

Voilà, vous avez fait le gros du boulot. Il ne reste plus qu'à donner les instruction pour la bonne exécution de ces plugins, via le fichier gulpfile.js.

Le fichier gulpfile.js

Le fichier gulpfile.js s'occupe de gérer les tâches à réaliser, leurs options, leurs sources et destination. Bref, c'est le chef d'orchestre (après vous).

Une tâche Gulp ressemble à ça :

gulp.task('css', function () {
  return gulp.src(ici-ma-source)
    /* ici les plugins Gulp à exécuter */
    .pipe(gulp.dest(ici-ma-destination));
});

Dans ce bout de code, voici ce qu'il faut retenir :

  • 'css' : le nom que l'on a donné à la tâche
  • ici-ma-source : chemin indiquant l'endroit où se trouve le(s) fichier(s) source à traiter
  • ici-ma-destination : chemin vers lequel les fichiers seront créés après l'exécution des tâches Gulp

Commençons par déclarer toutes les variables dont nous aurons besoin au début de notre fichier Gulpfile. Il s'agira des variables de plugins ainsi que le dosier de source et de destination :

// Requis
var gulp = require('gulp');

// Include plugins
var plugins = require('gulp-load-plugins')(); // tous les plugins de package.json

// Variables de chemins
var source = './src'; // dossier de travail
var destination = './dist'; // dossier à livrer

ll s'agit à présent de déclarer notre première tâche, celle de compiler notre fichier LESS en CSS...

Compiler LESS vers CSS

Le plugin permettant de compiler LESS vers CSS se nomme "gulp-less". Si tout va bien, nous l'avons déjà déclaré dans package.json et installé avec notre npm install. Sachez qu'un plugin équivalent existe bien évidemment pour compiler du langage Sass, il s'appelle - sans surprise - "gulp-sass".

Notre tâche Gulp s'écrira ainsi :

gulp.task('css', function () {
  return gulp.src(source + '/assets/css/styles.less')
    .pipe(plugins.less())
    .pipe(gulp.dest(destination + '/assets/css/'));
});

Comment exécuter cette tâche ? Tapez simplement :

gulp css

C'est tout !

gulp task

Notre CSS (.less) de départ :

@color: pink;
body {margin: 0;display: flex;
  background: red;z-index:1337; position:relative;
}
@media (min-width:640px) {
p {color: @color; box-shadow: 0 0 0 darken(@color, 30%)}
  }

Le fichier CSS résultant de cette tâche Gulp est généré dans le dossier de destination (chez nous "dist") :

body {
  margin: 0;
  display: flex;
  background: red;
  z-index: 1337;
  position: relative;
}
@media (min-width: 640px) {
  p {
    color: pink;
    box-shadow: 0 0 0 #ff274d;
  }
}

Parfait pour un début, continuons sur notre lancée !

Réordonner les propriétés

Étant un peu perfectionniste sur les bords chez Alsacréations, nous avons établi comme convention de toujours bien ordonner nos déclarations CSS au sein de leurs propriétés.

Cela nous évite de retrouver des propriétés primordiales perdues en plein milieu d'une très longue règle CSS, et nous facilite énormément la relecture et la maintenance dans l'équipe.

Le plugin "gulp-csscomb" est parfait pour cette mission !

La voici ajouté à notre tâche "css" initiale :

gulp.task('css', function () {
  return gulp.src(source + '/assets/css/styles.less')
    .pipe(plugins.less())
    .pipe(plugins.csscomb())
    .pipe(gulp.dest(destination + '/assets/css/'));
});

Le fichier CSS généré :

body
{
    position: relative;
    z-index: 1337;

    display: flex;

    margin: 0;

    background: red;
}
@media (min-width: 640px)
{
    p
    {
        color: pink;
        box-shadow: 0 0 0 #ff274d;
    }
}

C'est plutôt pas mal. Par contre, le plugin a un peu "cassé" notre joli code en créant des trous et des espaces superflus. Qu'à cela ne tienne, j'en profite pour caser un plugin de nettoyage.

Ré-indenter et reformater 

"gulp-cssbeautify" est un plugin dont l'action sera de faire le ménage dans votre code et de le rendre brillant comme un sou neuf, avec les espacements et les indentations parfaitement respectées.

Le voici en action (avec un choix d'indentation de 2 espaces) :

gulp.task('css', function () {
  return gulp.src(source + '/assets/css/styles.less')
    .pipe(plugins.less())
    .pipe(plugins.csscomb())
    .pipe(plugins.cssbeautify({indent: '  '}))
    .pipe(gulp.dest(destination + '/assets/css/'));
});

Et voici le résultat sur notre code obtenu à l'étape précédente :

body {
  position: relative;
  z-index: 1337;
  display: flex;
  margin: 0;
  background: red;
}

@media (min-width: 640px) {
  p {
    color: pink;
    box-shadow: 0 0 0 #ff274d;
  }
}

Ajouter automatiquement les préfixes CSS3

Vous aurez constaté que certains déclarations telles que display: flex; ont été conservées telles quelles sans ajouter les préfixes pour les anciens navigateurs.

Cette tâche d'ajout de préfixes, très pénible à la main, peut être rendue complètement transparente grâce au plugin "gulp-autoprefixer". Celui-ci se charge d'ajouter les préfixes uniquement lorsque nécessaire et avec une redoutable efficacité. Sachez aussi que Autoprefixer peut être configuré pour tenir compte de navigateurs exotiques qui feraient partie de votre cible, s'il le faut.

Ajoutons gulp-autoprefixer à notre liste de tâches CSS :

gulp.task('css', function () {
  return gulp.src(source + '/assets/css/styles.less')
    .pipe(plugins.less())
    .pipe(plugins.csscomb())
    .pipe(plugins.cssbeautify({indent: '  '}))
    .pipe(plugins.autoprefixer())
    .pipe(gulp.dest(destination + '/assets/css/'));
});

Le contenu du fichier CSS généré dans le dossier de destination devient :

body {
  position: relative;
  z-index: 1337;
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  margin: 0;
  background: red;
}

@media (min-width: 640px) {
  p {
    color: pink;
    box-shadow: 0 0 0 #ff274d;
  }
}

Et voilà le travail : toutes ces actions sont enchaînées sur une simple exécution de la commande gulp css !

Minifier CSS

Il nous reste une dernière tâche à mener pour disposer d'un véritable fichier CSS de production : celle de le minifier pour qu'il n'occupe que le poids minimal. Il existe de nombreux plugins pour cela, mais "gulp-csso" a notre préférence actuellement.

Par contre, à présent que nous venons de générer un très beau code CSS parfaitement ordonné et lisible, c'est un peu dommage de tout casser en le rendant illisible par un être humain.

Nous allons donc scinder notre tâche initiale en deux tâches distinctes :

  • une tâche "css" qui produira un fichier CSS propre et lisible au sein de notre dossier "dist" (styles.css)
  • une tâche "minify" qui compressera et produira un fichier styles.min.css aux côtés de notre joli fichier styles.css

Notre tâche de minification s'écrira ainsi :

// Tâche "minify" = minification CSS (destination -> destination)
gulp.task('minify', function () {
  return gulp.src(destination + '/assets/css/*.css')
    .pipe(plugins.csso())
    .pipe(plugins.rename({
      suffix: '.min'
    }))
    .pipe(gulp.dest(destination + '/assets/css/'));
});

Cette tâche s'exécutera à l'aide de la commande suivante, comme vous vous en doutez :

gulp minify

Au final : tâches de build, de prod et par défaut

Je pense à présent que vous avez bien saisi le concept général de Gulp et de ses tâches.

Vous imaginez bien que ce que l'on vient de réaliser du côté CSS est parfaitement envisageable avec :

  • JavaScript (concaténation de fichiers multiples, minification)
  • images (optimisation des poids)
  • polices de caractères
  • etc.

Vous vous donner une idée des tâches utiles pouvant être réalisées avec Gulp, je vous invite à consulter l'article détaillé "Ébauche de workflow Gulp : tâches courantes, unCSS, includes HTML et critical-CSS".

En vue de pouvoir regrouper ces différentes tâches, nous pourrions créer une tâche générale "build" et une autre tâche "prod". La dernière étant prévue pour obtenir des fichiers directement à livrer au client final (par exemple avec des CSS minifiés) :

// Tâche "build"
gulp.task('build', ['css']);

// Tâche "prod" = Build + minify
gulp.task('prod', ['build',  'minify']);

// Tâche par défaut
gulp.task('default', ['build']);

Notez que la déclaration d'une tâche par défaut (ici associée à build), permet de se contenter de la syntaxe de commande gulp au-lieu de gulp build.

Et une tâche de surveillance automatique !

Parvenu à la fin de cette introduction à Gulp, j'ai failli oublier une tâche essentielle et qui va grandement vous faciliter la vie : la tâche de surveillance automatique ("watch").

Cette fonction de survellance est directement intégrée à Gulp (pas besoin de plugin) et permettra de détecter toute modification de contenu d'un fichier et de lancer automatiquement une tâche prévue, sans avoir besoin de systématiquement lancer à la main un gulp ou un gulp css ou un gulp build. Génial !

Voici un exemple de tâche de "watch". Elle surveille tous les fichiers .less dans la source et lance automatiquement la tâche build :

// Tâche "watch" = je surveille *less
gulp.task('watch', function () {
  gulp.watch(source + '/assets/css/*.less', ['build']);
});

Le fichier gulpfile.js final

Voici le fichier gulpfile.js complet :

// Requis
var gulp = require('gulp');

// Include plugins
var plugins = require('gulp-load-plugins')(); // tous les plugins de package.json

// Variables de chemins
var source = './src'; // dossier de travail
var destination = './dist'; // dossier à livrer

// Tâche "build" = LESS + autoprefixer + CSScomb + beautify (source -> destination)
gulp.task('css', function () {
  return gulp.src(source + '/assets/css/styles.less')
    .pipe(plugins.less())
    .pipe(plugins.csscomb())
    .pipe(plugins.cssbeautify({indent: '  '}))
    .pipe(plugins.autoprefixer())
    .pipe(gulp.dest(destination + '/assets/css/'));
});

// Tâche "minify" = minification CSS (destination -> destination)
gulp.task('minify', function () {
  return gulp.src(destination + '/assets/css/*.css')
    .pipe(plugins.csso())
    .pipe(plugins.rename({
      suffix: '.min'
    }))
    .pipe(gulp.dest(destination + '/assets/css/'));
});

// Tâche "build"
gulp.task('build', ['css']);

// Tâche "prod" = Build + minify
gulp.task('prod', ['build',  'minify']);

// Tâche "watch" = je surveille *less
gulp.task('watch', function () {
  gulp.watch(source + '/assets/css/*.less', ['build']);
});

// Tâche par défaut
gulp.task('default', ['build']);

J'espère que cette introduction satisfera vos attentes ou du moins votre curiosité, et que l'usage de cet outil améliorera votre façon de travailler au quotidien... en attendant d'autres outils nouveaux à venir.

Si le coeur vous en dit, je partage un fichier Gulp un peu plus complet (avec des tâches dans différents domaines) dont il ne tient qu'à vous de le consulter, le décortiquer et de vous l'approprier.

Commentaires

C'est toujours pratique en effet, perso, j'ai fait un petit script basé sur Gulp que je pose dans les dossiers d'export de mon graphiste, il optimise tout ce qu'il exporte en continu. C'est basique, mais ça fait gagner du temps.

« si vous êtes sur Mac ou Linux, vous aurez sans doute besoin de faire précéder cette syntaxe d'un sudo.. »
Ben de toutes façons, pour exécuter 'npm' faut être sur un Unix-like, non ?
Pasque moi, sur mon Windows, sans installer un truc comme cygwin, npm, y'a pas !

Bon, critique voilée (mais on voit le visage) à part, c'est bien vrai que Gulp est un bel outil comme on aimerait en voir plus souvent.

@ObiwanKennedy : ah non, j'ai bien npm sur mon windows (et bower et git) sans avoir installé cygwin.
EDIT : et je ne trouve aucun article qui dit que cygwin serait nécessaire.
Au contraire : http://blog.lesieur.name/installer-et-utiliser-nodejs-sous-windows/

@Raphael : ah d'accord ! Encore eusse-t-il fallu que j'installe node.js ! ;-) Car npm vient avec.
Avec toutes mes confuses pour l'émission mal venue de de gros doute.

Et j'ajoute que j'utilise Gulp et d'autres bricoles dans mon environnement de dev qui tourne dans une machine virtuelle sous un Linux. Ce qui explique que je ne n'aie pas installé node.js sur mon Windows.

@Raphael depuis que je me suis formé chez vous je l'utilise dans tous mes projets web
mais j'ai une question comment surveiller la "gulp watch" car lorsqu'une erreur de syntaxe css est compilé, gulp plante et je suis obligé de relancer via le terminal (mac) la commande watch gulp

merci

Merci beaucoup pour cet article très clair. Ca me motive pour m'y mettre.

Vous devriez être remboursé par le sécu, tellement vous faites du bien !
Marco

Merci pour cet article !

ça va faire quelques semaines que j'utilise Gulp et je dois dire que le tutoriel précédent et celui ci m'ont changé la façon de bosser, cependant je suis confronté à un petit problème concernant les fichiers php.

La tâche "uncss" par exemple n'est compatible qu'avec les fichiers html. D'autres tâches comme "critical" s'amusent à modifier la syntaxe php etc. Bref c'est problématique.

La seule solution que j'ai trouvé est d'utiliser les tâches "rename" et "replace" pour mettre en commentaire les tags php et renommer les fichiers .php en .html. Puis d'effectuer l'opération inverse lors de la tâche de mise en prod. Mais ça me parait moyen moyen...

Quelqu'un aurait-il une meilleure solution par hasard ? Merci :)

Un truc sympa aussi c'est la fabrication automatique de font via le plugin gulp-iconfont de Nicolas Froidure. Je l'ai paramétré pour que les différents formats de font se créés à partir de tous les .svg déposés dans un dossier (et pléalablement optimisé via gulp-imagemin). Et, tant qu'à faire, j'ai fais un template lodash avec gulp-consolidate pour générer automatiquement tout le css associé lors de chaque changement d'icône pour la police... ainsi que le html de ma page d'exemple.

@pifoux : Wow merci beaucoup, c'est un peu exagéré non ? :)

@psykhe : effectivement, je ne sais pas si Critical et unCSS sont très pratiques avec PHP (nous on ne les utilise pas sur ce type de fichiers). Par contre s'il ne s'agit que de faire des include, on reste en HTML et on utilise le plugin décrit dans l'article sur le workflow gulp.

Longtemps réfractaire aux lignes de commande, je me suis mis aux task managers avec Gulp. Au final ça se fait bien simplement et le gain est très très notable ! Il faut juste ce forcer à passer le pas au début.

Bonjour !
Je me demandais, pourquoi faut-il créer des dossiers "dist", "src" ou "assets" ?

Merci pour ce tuto sinon !

Salut DavidF,
Petite réponse vite fait : pour séparer la source (le code de base) de la destination (l'emplacement à partir duquel tu déploies). Pour moi, deux éléments indispensables.
Assets pourrait quant à lui être mis en parallèle avec des répertoires doc, ... et autres (selon l'organisation que tu désires avoir)

Perso, j'avais une autre question : dans gulpfile.js final, on surveille l'ensemble des fichiers *.less dans le répertoire source. Cependant, le build, qui appelle le CSS, ne traite que le fichier styles.css. Etant nouveau dans gulp (et clairement, j'ai été bluffé par ce tuto), je me demandais comment faire pour ne traiter **que** le fichier détecté comme étant modifié. Je suppose que le "piping" de gulp permet de le faire, mais comment ?

Merci d'avance !

Bonjour,
@Raphael : Merci pour ton article très enrichissant. J'ai juste une petite remarque concernant la tâche "prod". "build" et "minify" sont exécutées parallèlement mais si j'ai bien compris, devraient être séquencées (build puis minify).
Pour ce faire, j'utilise le plugin "gulp-run-sequence" (il y a sans doute d'autres solutions) :
var runSequence = require('gulp-run-sequence');
gulp.task('prod', runSequence('build', 'minify'), function() {
});

Hello!

J'essaie de faire tourner Gulp sous mac, mais je reçois une erreur et ne sais pas du tout comment la résoudre. Auriez vous la gentillesse de m'aider, svp?

Merci d'avance!

"

MacBook-Pro-de-Jarl:frontend-framework jarlmiailhehelin$ gulp

[13:30:05] Local gulp not found in ~/www/frontend-framework

[13:30:05] Try running: npm install gulp

MacBook-Pro-de-Jarl:frontend-framework jarlmiailhehelin$ npm install --save-dev gulp

> fsevents@1.2.9 install /Users/jarlmiailhehelin/www/frontend-framework/node_modules/fsevents

> node install

node-pre-gyp WARN Using needle for node-pre-gyp https download

node-pre-gyp WARN Pre-built binaries not installable for fsevents@1.2.9 and node@10.16.0 (node-v64 ABI, unknown) (falling back to source compile with node-gyp)

node-pre-gyp WARN Hit error socket hang up

[Restauré 4 juin 2019 à 15:21:53]

Last login: Tue Jun 4 15:21:43 on console

MacBook-Pro-de-Jarl:frontend-framework jarlmiailhehelin$

"

Désolé, mauvaises lignes = >

MacBook-Pro-de-Jarl:frontend-framework jarlmiailhehelin$ gulp

[13:25:00] Using gulpfile ~/www/frontend-framework/gulpfile.js

[13:25:00] Starting 'default'...

hello world

[13:25:00] The following tasks did not complete: default

[13:25:00] Did you forget to signal async completion?

@pellehelin : Hello, je pense que tu as installé gulp 4, alors que le tuto donne une syntaxe pour gulp 3. Il va falloir adapter le code je présume. En tout cas, je vais ajouter un bandeau pour prévenir les prochains lecteurs.

@Raphael : en effet, ça doit être mon souci. Bon, je ne saurais pas du tout adapter le code à mon niveau d'expertise de quais-nul. Je vais investiguer. Merci!

Commenter

Vous devez être inscrit et identifié pour utiliser cette fonction.

Connectez-vous (déjà inscrit)

Oubli de mot de passe ? Pas de panique, on va le retrouver

Pas encore inscrit ? C'est très simple et gratuit.