Avec Grunt, Gulp est l'un des principaux task runners utilisés aujourd'hui. Le formidable Zell Liew présente de manière claire et complète cet outil de développement qui vous facilitera la vie.
Par Zell Liew
Note de Chris Coyier : Zell a un style de tutoriel bien à lui (voir son tuto Découvrir Susy) qui se prête bien à des sujets de cette ampleur. Je me suis attaqué à Grunt dans mon article Grunt pour ceux qui pensent que Grunt est compliqué et j’ai l’impression que les lecteurs l’ont trouvé bien utile, alors on recommence avec Gulp qui est tout aussi populaire que Grunt !
Gulp est un task runner c’est à dire qu’il effectue des tâches pour vous. Dans le développement web, vous l’utiliserez pour des tâches front-end telles que :
- créer un serveur web local
- rafraîchir le navigateur automatiquement à chaque fois qu’un fichier est modifié
- utiliser des préprocesseurs comme Sass ou LESS
- optimiser des ressources comme CSS, JavaScript et les images.
La liste est longue de ce que Gulp peut faire pour vous (les dingos comme moi l’utilisent pour construire des générateurs de sites statiques). Cet article est un guide d’introduction à Gulp qui vous aidera à construire vos propres process de construction. Si j’ai bien fait mon boulot dans ce tutoriel, vous maîtriserez les bases de Gulp et vous aurez les outils pour aller plus loin.
Avant de commencer, voyons pourquoi vous pourriez utiliser Gulp plutôt que d’autre outils.
Pourquoi utiliser Gulp ?
Les outils comme Gulp sont souvent appelés des outils de développement ou de construction (build tools) car ils effectuent automatiquement un certain nombre de tâches nécessaires à la construction d’un site web. Les deux outils les plus populaires sont Gulp et Grunt, mais il y en a d’autres, comme Broccoli. Ce dernier se concentre sur la compilation de ressources, une des tâches les plus courantes.
Il existe déjà de nombreux articles expliquant les différences entre Grunt et Gulp, notamment celui-ci, celui-là ou encore cet autre. Brunch est un autre outil qui se concentre également sur les ressources et contient quelques-unes des tâches plus courantes telles que le serveur local et l’observation des modifications de fichiers, cette page présente les arguments en faveur de Brunch.
La principale différence entre eux réside dans la façon de configurer un workflow. Les configurations de Gulp sont généralement plus simples que celles de Grunt. Gulp est également plus rapide.
Et maintenant, commençons !
Ce que nous allons réaliser
À la fin de ce tutoriel, vous aurez un workflow comprenant les tâches détaillées au début de cet article :
- créer un serveur web local
- compiler Sass en CSS
- rafraîchir le navigateur automatiquement à chaque fois qu’un fichier est modifié
- optimiser toutes les ressources (CSS, JS, fonts, images).
Vous apprendrez également comment enchaîner différentes tâches dans des commandes simples, faciles à comprendre et à exécuter.
Mais d’abord, installons Gulp sur notre ordinateur.
Installer Gulp
Vous aurez besoin de Node.js sur votre ordi. Si vous ne l’avez pas déjà, il suffit d’aller sur le site de Node et de télécharger le package installer.
Une fois Node installé, vous pouvez installer Gulp en utilisant la commande suivante dans votre interface en ligne de commande ( NdT : si vous n’êtes pas familier de la chose, vous pouvez consulter l’article La console, une introduction).
$ npm install gulp -g
NB : les utilisateurs de Mac auront besoin du mot-clé "sudo" avant (il faudra donc taper sudo npm install gulp -g
), pour vous en passer vous pouvez consulter cet article. Et juste un rappel : le "$" symbolise l’invite de commande, il ne fait pas partie de la commande que vous tapez.
Le flag -g
de cette commande indique à npm que Gulp doit être installé globalement, ce qui permet d’utiliser la commande gulp
depuis n’importe où sur votre système.
Créons maintenant un projet qui utilise Gulp.
Créer un projet Gulp
Pour commencer, nous allons créer un dossier que nous appellerons (par exemple) project
qui sera la racine de notre projet pour ce tutoriel. Lancez la commande run init
depuis ce dossier :
...placez-vous sur le dossier project en tapant cd suivi d’un espace suivi du chemin d’accès au dossier
$ npm init
NdT : si vous rencontrez un problème, reportez-vous à l’article sur Grunt, partie “installation”, voir le gif intitulé “pour les ploucs de la console”.
La commande npm init
crée un fichier package.json
pour project, qui enregistre les infos relatives à votre projet, telles que les dépendances utilisées (Gulp est un exemple de dépendance).
npm init
vous renverra le message suivant :

Une fois le fichier package.json
créé, nous pouvons installer Gulp dans le projet avec la commande suivante :
npm install gulp --save-dev
Cette fois-ci, nous installons Gulp dans le dossier project
et non pas globalement, c’est pourquoi la commande est différente.
Comme vous le constatez, le mot-clé sudo
n’est pas nécessaire (pour les utilisateurs de Mac) du fait que l’installation n’est pas globale. On ajoute --save-dev
pour dire d’ajouter gulp
comme dépendance de développement (devDependencies) dans package.json
.

Si vous jetez un coup d’oeil maintenant à votre dossier project
vous verrez que Gulp a créé un dossier node_modules
ainsi qu’un fichier gulp
à l’intérieur de node_modules
.

Nous sommes presque prêts, il nous reste un point : déterminer la structure du projet.
La structuration de nos dossiers
Gulp est très flexible et nous donne la possibilité de structurer le projet comme bon nous semble. Pour ce faire, il nous faut juste comprendre la logique avant de peaufiner notre projet.Pour cet article, j’utiliserai la structure d’une webapp générique :
|- app/
|- css/
|- fonts/
|- images/
|- index.html
|- js/
|- scss/
|- dist/
|- gulpfile.js
|- node_modules/
|- package.json
Dans cette structure, nous utilisons le dossier app
pour le développement, le dossier dist
(pour “distribution”) contenant lui les fichiers optimisés pour le site en production.
Puisque app
est utilisé pour le développement, c’est là que se trouvera notre code.
Nous devrons garder cette structure à l’esprit lorsque nous travaillerons sur les configurations Gulp. Et maintenant, nous allons créer notre première tâche dans gulpfile.js
qui contient nos configurations.
(publicité)
Notre première tâche Gulp
Lorsqu’on utilise Gulp, la première étape consiste à le requérir (require) dans le gulpfile.
//JS
var gulp = require('gulp');
La déclaration require indique à Node d’aller chercher dans node_modules
un package appelé gulp
. Une fois trouvé, nous attribuons son contenu à la variable gulp
.
Écrivons maintenant une tâche gulp avec cette variable gulp
. Voici la syntaxe de base d’une tâche gulp :
//
gulp.task('nom-de-la-tache', function() {
// quelque chose
});
Le nom-de-la-tache
sera toujours être utilisé lorsque vous voulez lancer une tâche. Par exemple, vous pourrez lancer cette tâche dans la console en écrivant :
$ gulp nom-de-la-tache
Pour faire un test, créons une tâche intitulée hello
qui affichera le message “Hello Zell” :
//JS
gulp.task('hello', function() {
console.log('Hello Zell');
});
Nous pouvons lancer cette tâche via la console :
$ gulp hello
et la console nous retourne un log qui dit Hello Zell
:

Bon, les tâches Gulp sont en général un peu plus compliquées que cela, elles contiennent deux méthodes gulp ainsi qu’un tas de plugins. Voici à quoi ça ressemble :
//JS
gulp.task('task-name', function () {
return gulp.src('source-files') // Get source files with gulp.src
.pipe(aGulpPlugin()) // Sends it through a gulp plugin
.pipe(gulp.dest('destination')) // Outputs the file in the destination folder
})
Comme vous le voyez, une tâche réelle prend deux méthodes gulp : gulp.src
et gulp.dest
.
gulp.src
indique à la tâche gulp quels fichiers utiliser pour la tâche, tandis que gulp.dest
indique où mettre les fichiers qui résultent de l’exécution de la tâche.
Nous allons réaliser une vraie tâche, de compilation de fichiers Sass en CSS.
Preprocessing avec Gulp
Nous pouvons compiler Sass en CSS avec Gulp, grâce à un plugin nommé gulp-sass. Vous pouvez installer gulp-sass dans votre projet via la commande npm install
tout comme nous l’avons fait pour gulp
, sans oublier le flag --save-dev
qui ajoutera le plugin aux dépendances de développement dans package.json
.
$ npm install gulp-sass --save-dev
Pour pouvoir l’utiliser, nous devons ensuite requérir (require
) gulp-sass depuis le dossier node_modules
où il a été installé, comme nous l’avons fait avec gulp
.
//JS
var gulp = require('gulp');
// Requires the gulp-sass plugin
var sass = require('gulp-sass');
Nous pouvons utiliser gulp-sass en remplaçant aGulpPlugin()
par sass()
. Et puisque la tâche est censée compiler Sass en CSS, appelons-la sass
.
//JS
gulp.task('sass', function(){
return gulp.src('source-files')
.pipe(sass()) // ici on utilise gulp-sass
.pipe(gulp.dest('destination'))
});
Nous devons fournir des fichiers source ainsi qu’une destination, donc créons un fichier styles.scss
dans le dossier app/scss
. Ce fichier sera ajouté à la tâche sass
dans gulp.src
.
Nous voulons que le résultat éventuel styles.css
se retrouve dans le dossier app/css
qui sera donc la “destination” de gulp.dest
.
//JS
gulp.task('sass', function(){
return gulp.src('app/scss/styles.scss')
.pipe(sass()) // Converts Sass to CSS with gulp-sass
.pipe(gulp.dest('app/css'))
});
Pour tester notre tâche, nous allons ajouter un contenu Sass à notre fichier styles.scss
.
//SCSS
// styles.scss
.testing {
width: percentage(5/7);
}
Si nous lançons gulp sass
dans la console, nous pouvons constater qu’un fichier styles.css
a été créé dans app/css
. De plus, son contenu est une valeur 71.4287%
correspondant à l’évaluation de percentage(5/7)
.
//CSS
/* styles.css */
.testing {
width: 71.42857%;
}
Pour info : gulp-sass utilise LibSass pour convertir Sass en CSS. C’est beaucoup plus rapide que les méthodes basées sur Ruby, mais si vous le souhaitez vous pouvez utiliser ces dernières avec gulp-ruby-sass ou gulp-compass.
Parfois, nous avons besoin de compiler plus d’un fichier .scss
en CSS. Nous pouvons le faire, en une seule fois, via les globs de Node.
Globbing avec Node
Les globs sont des patterns de correspondance qui fonctionnent un peu comme les regex mais spécifiquement pour les chemins d’accès.
La plupart des workflows de gulp feront appel à 4 globs seulement :
*.scss
: le pattern*
est une sorte de “joker” qui correspond à n’importe quel pattern dans le dossier courant. Dans cet exemple, tous les fichiers ayant une extension.scss
dans le dossier racineproject
.**/*.scss
: c’est une version plus extrême du pattern précédent, qui cible tous les fichiers ayant une extension.scss
dans le dossier racine et dans n’importe quel dossier enfant.!pas-moi.scss
: le!
indique que Gulp doit exclure ce pattern, ce qui est utile si vous voulez exclure un fichier au sein d’un pattern. Dans notre exemple, le fichierpas-moi.scss
sera exclu.*.+(scss|sass)
: le plus+
et les parenthèses()
permettent à Gulp de cibler des patterns multiples, chaque pattern étant séparé des autres par un caractère “barre verticale”|
(sur un clavier Mac, faire ⇧ + ⌥ + l). Dans notre exemple, Gulp ciblera tous les fichiers ayant une extension.scss
ou.sass
dans le dossier racine.
Nous pouvons maintenant remplacer app/scss/styles.scss
par un pattern scss/**/*.scss
qui matchera tous les fichiers ayant une extension .scss
dans app/scss
ou dans un dossier enfant.
//JS
gulp.task('sass', function() {
return gulp.src('app/scss/**/*.scss') // Gets all files ending with .scss in app/scss and children directories
.pipe(sass())
.pipe(gulp.dest('app/css'))
})
Tout autre fichier Sass trouvé dans app/scss
sera automatiquement inclus dans la tâche. Si vous ajoutez un fichier print.scss
, vous verrez que print.css
sera généré à l’intérieur de app/css
.

Nous savons maintenant comment compiler tous les fichiers Sass avec une commande unique. Mais bon, ce travail manuel est un peu fastidieux, n’est-ce pas ? Heureusement, Gulp peut lancer cette tâche automatiquement à chaque fois qu’un fichier est sauvegardé, à travers un processus appelé “watching” (observation).
Observer les modifications de fichiers
Gulp propose une méthode watch
qui suit les modifications de fichiers. La syntaxe de la méthode watch
est la suivante :
//JS
gulp.watch('fichiers-a-suivre', ['tache1', 'tache2', 'tache3']);
Si nous voulons observer tous les fichiers Sass et lancer la tâche sass
à chaque fois qu’un fichier Sass est sauvegardé, il nous suffit de remplacer fichiers-a-suivre
par app/scss/**/*.scss
et ['tache1', 'tache2', 'tache3']
par ['sass'] :
//JS
gulp.watch('app/scss/**/*.scss', ['sass']);
Le plus souvent, nous voudrons observer plus d’un type de fichier à la fois. Pour cela, nous pouvons regrouper plusieurs processus dans une même tâche watch
:
//JS
gulp.task('watch', function(){
gulp.watch('app/scss/**/*.scss', ['sass']);
// autres observations
})
Si vous lancez la commande gulp watch
maintenant, vous verrez que Gulp commence son observation immédiatement.

Dès que vous sauvegardez un fichier .scss
Gulp lance automatiquement la tâche sass
.

Allons plus loin et demandons à Gulp de rafraîchir le navigateur à chaque fois que nous sauvegardons un fichier .scss
, grâce à Browser Sync.
Rafraîchissement en live avec Browser Sync
Browser Sync simplifie le développement web en créant un serveur web nous permettant un rafraîchissement live. Il offre par ailleurs d’autres fonctionnalités, par exemple la synchronisation sur plusieurs devices.
Installons d’abord Browser Sync :
$ npm install browser-sync --save-dev
Vous avez sans doute remarqué qu’il n’y a pas de préfixe gulp-
: Browser Sync fonctionne avec Gulp, c’est pourquoi nous n’avons pas à utiliser de plugin. Il nous faut, comme d’habitude, requérir Browser Sync :
//JS
var browserSync = require('browser-sync');
Nous créons une tâche browserSync
pour permettre la création d’un serveur, et nous indiquons à Browser Sync où doit se trouver la racine du serveur. Dans notre cas, c’est le dossier app
:
//JS
gulp.task('browserSync', function() {
browserSync({
server: {
baseDir: 'app'
},
})
})
Il nous faut modifier légèrement notre tâche sass
afin que Browser Sync puisse injecter les nouveaux styles CSS (c’est à dire mettre à jour CSS) dans le navigateur à chaque fois que la tâche sass
est lancée.
//JS
gulp.task('sass', function() {
return gulp.src('app/scss/**/*.scss') // Gets all files ending with .scss in app/scss
.pipe(sass())
.pipe(gulp.dest('app/css'))
.pipe(browserSync.reload({
stream: true
}))
});
Et voilà, la configuration de Browser Sync est terminée. Maintenant, nous devons lancer à la fois watch
et browserSync
en même temps pour un rafraîchissement en live.
Il serait évidemment lourd d’ouvrir deux consoles séparées pour lancer les deux tâches, donc demandons à Gulp de la lancer toutes les deux en indiquant que browserSync
doit être achevée avant que watch
soit lancée. Pour cela, on ajoute un deuxième argument à la tâche watch
, en suivant cette syntaxe :
//JS
gulp.task('watch', ['array', 'of', 'tasks', 'to', 'complete','before', 'watch'], function (){
// ...
})
Ici, nous ajoutons la tâche browserSync
:
//JS
gulp.task('watch', ['browserSync'], function (){
gulp.watch('app/scss/**/*.scss', ['sass']);
// Other watchers
})
Nous voulons également nous assurer que sass
est lancé avant watch
, de sorte que CSS sera toujours le dernier quelle que soit la commande lancée.
//JS
gulp.task('watch', ['browserSync', 'sass'], function (){
gulp.watch('app/scss/**/*.scss', ['sass']);
// Other watchers
});
À présent, si vous lancez gulp watch
, Gulp lancera les deux tâches sass
et browserSync
simultanément, et lorsqu’elles sont toutes deux achevées, watch
est lancé.

En même temps, une fenêtre de navigateur pointant vers app/index.html
s’ouvre. Si vous modifiez le fichier styles.scss
, vous verrez que le navigateur est automatiquement rafraîchi.

Encore une chose avant de clore ce chapitre. Puisque nous observons déjà nos fichiers .scss
pour le rafraîchissement, pourquoi ne pas faire de même avec les fichiers HTML ou JavaScript ?
Nous pouvons le faire en ajoutant deux processus watch
et en appelant la fonction browserSync.reload
lorsqu’un fichier est sauvegardé.
//JS
gulp.task('watch', ['browserSync', 'sass'], function (){
gulp.watch('app/scss/**/*.scss', ['sass']);
// Reloads the browser whenever HTML or JS files change
gulp.watch('app/*.html', browserSync.reload);
gulp.watch('app/js/**/*.js', browserSync.reload);
});
Jusqu’ici dans ce tutoriel nous avons réalisé 3 choses :
- Créer un serveur pour le développement web
- Utiliser le préprocesseur Sass
- Rafraîchir le navigateur lorsqu’un fichier est sauvegardé
Passons maintenant à l’optimisation des ressources. Nous commencerons avec l’optimisation des fichiers CSS et JavaScript.
(publicité)
Optimiser les fichiers CSS et JavaScript
Optimiser CSS et JavaScript pour la production consiste essentiellement à minifier et concaténer les fichiers. Un des problèmes qui se posent lorsqu’on automatise ce process est l’ordre de concaténation. Admettons que nous ayons 3 scripts dans index.html
:
//HTML
<body>
<!-- other stuff -->
<script src="js/lib/a-library.js"></script>
<script src="js/lib/another-library.js"></script>
<script src="js/main.js"></script>
</body>
Ces scripts proviennent de deux dossiers différents. Il sera difficile de les concaténer à l’aide de plugins traditionnels comme gulp-concatenate.
Heureusement, il existe un plugin Gulp bien pratique, gulp-useref, qui résout ce problème.
gulp-useref concatène tous les fichiers CSS ou JavaScript en un seul, via une syntaxe commençant par <!--build:
et se terminant par <!--endbuild-->
:
//HTML
<!-- build:<type> <path> -->
... HTML Markup, liste de scripts / liens
<!-- endbuild -->
<type>
peut être js
, css
ou remove
. Si vous utilisez ce dernier, Gulp éliminera le bloc de construction sans générer de fichier.
<path>
correspond au chemin d’accès du fichier qui sera généré.
Dans l’exemple qui suit, nous voulons générer un fichier JavaScript main.min.js
dans le dossier dist/js
:
//HTML
<!--build:js js/main.min.js -->
<script src="js/lib/a-library.js"></script>
<script src="js/lib/another-library.js"></script>
<script src="js/main.js"></script>
<!-- endbuild -->
Configurons mainenant le plugin gulp-useref dans notre gulpfile. Nous devons d’abord installer le plugin...
$ npm install gulp-useref --save-dev
...et le requérir dans gulpfile.
//JS
var useref = require('gulp-useref');
Pour définir une tâche useref
, on procède comme nous l’avons déjà fait, mais il nous faut appeler la fonction useref.assets()
avant gulp.src
comme ceci :
//JS
gulp.task('useref', function(){
var assets = useref.assets();
return gulp.src('app/*.html')
.pipe(assets)
.pipe(assets.restore())
.pipe(useref())
.pipe(gulp.dest('dist'))
});
Et maintenant, si vous lancez cette tâche useref
, Gulp va chercher les 3 scripts et les concaténer dans dist/js/main.min.js
.

À ce stade toutefois le fichier n’est pas minifié. Pour ce faire, nous utilisons le plugin gulp-uglify :
$ npm install gulp-uglify --save-dev
puis :
//JS
// Les autres requires...
var uglify = require('gulp-uglify');
gulp.task('useref', function(){
var assets = useref.assets();
return gulp.src('app/*.html')
.pipe(assets)
.pipe(uglify()) // pour minifier les fichiers Javascript
.pipe(assets.restore())
.pipe(useref())
.pipe(gulp.dest('dist'))
});
Gulp minifiera automatiquement le fichier main.min.js
à chaque fois que vous lancerez la tâche useref
.
Une dernière chose sympa avec gulp-useref est qu’il modifie automatiquement tous les scripts situés à l’intérieur de <!--build:
et <!--endbuild-->
en un seul fichier JavaScript pointant vers js/main.min.js
.

Génial, non ?
Nous pouvons utiliser la même méthode pour concaténer et minifier nos fichiers CSS (si vous en avez plus d’un). Nous suivront le même processus, consistant à ajouter un commentaire build
:
//HTML
<!--build:css css/styles.min.css-->
<link rel="stylesheet" href="css/styles.css">
<link rel="stylesheet" href="css/another-stylesheet.css">
<!--endbuild-->
La tâche useref
doit être légèrement modifiée puisque nous avons maintenant des fichiers CSS. Nous ne voulons pas lancer uglify()
sur les fichiers CSS parce que ça ne va pas leur faire de bien... Donc nous voulons qu’uglify
ne minifie que les fichiers JavaScript, et pour cela nous allons faire appel au plugin gulp-if.
$ npm install gulp-if --save-dev
...qui nous permet d’indiquer une condition comme suit :
//JS
// Les autres requires...
var gulpIf = require('gulp-if');
gulp.task('useref', function(){
var assets = useref.assets();
return gulp.src('app/*.html')
.pipe(assets)
// Minifie seulement les fichiers Javascript
.pipe(gulpIf('*.js', uglify()))
.pipe(assets.restore())
.pipe(useref())
.pipe(gulp.dest('dist'))
});
Nous pouvons minifier les fichiers CSS avec gulp-useref également, mais nous utilisons le plugin gulp-minify-css pour cela.
$ npm install gulp-minify-css
puis :
//JS
var minifyCSS = require('gulp-minify-css');
gulp.task('useref', function(){
var assets = useref.assets();
return gulp.src('app/*.html')
.pipe(assets)
// Minifie seulement les fichiers CSS
.pipe(gulpIf('*.css', minifyCSS()))
// Minifie seulement les fichiers Javascript
.pipe(gulpIf('*.js', uglify()))
.pipe(assets.restore())
.pipe(useref())
.pipe(gulp.dest('dist'))
});
À présent, à chaque fois que vous lancerez la tâche useref
, vous aurez un fichier CSS optimisé et un fichier JavaScript optimisé.
Passons maintenant à l’optimisation des images.
Optimiser les images
Comme vous l’avez sans doute déjà deviné, nous allons utiliser le plugin gulp-imagemin.
$ npm install gulp-imagemin --save-dev
puis :
//JS
var imagemin = require('gulp-imagemin');
Avec gulp-imagemin, nous pouvons minifier les png
, les jpg
, les gif
et même les svg
. Créons une tâche images
à cet effet :
//JS
gulp.task('images', function(){
return gulp.src('app/images/**/*.+(png|jpg|gif|svg)')
.pipe(imagemin())
.pipe(gulp.dest('dist/images'))
});
Du fait que différents types de fichiers peuvent être optimisés différemment, vous aurez peut être besoin d’ajouter des options à imagemin
pour personnaliser l’optimisation.
Par exemple, vous pouvez créer des GIFs entrelacés (technique d’affichage progressif d’une image matricielle) via l’option interlaced
réglée sur true
.
//JS
gulp.task('images', function(){
return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)')
.pipe(imagemin({
interlaced: true
}))
.pipe(gulp.dest('dist/images'))
});
Vous pouvez explorer les autres options pour approfondir le sujet. L’optimisation des images est un processus assez long et il est souhaitable de ne pas le répéter lorsque ce n’est pas nécessaire. Pour cela, nous utiliserons le plugin gulp-cache.
$ npm install gulp-cache --save-dev
puis :
//JS
var cache = require('gulp-cache');
gulp.task('images', function(){
return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)')
// Met en cache les images passées par imagemin
.pipe(cache(imagemin({
interlaced: true
})))
.pipe(gulp.dest('dist/images'))
});
Nous avons presque terminé le processus d’optimisation. Il nous reste un dossier à transférer de app
vers dist
, c’est le dossier des polices de caractères (fonts).
Copier les fonts vers dist
Les fonts sont déjà optimisées, donc nous n’avons rien de particulier à faire. Il nous faut juste les copier dans dist
.
Nous pouvons copier des fichiers avec Gulp sans plugin, simplement en spécifiant les gulp.src
et gulp.dest
.
//JS
gulp.task('fonts', function() {
return gulp.src('app/fonts/**/*')
.pipe(gulp.dest('dist/fonts'))
})
Gulp copiera fonts
depuis app
vers dist
à chaque fois que vous lancerez la tâche fonts
.

Nous avons 6 tâches différentes dans notre gulpfile et chacune doit être appelée individuellement dans la console, ce qui n’est vraiment pas pratique. Nous allons voir comment lier ces tâches dans une seule commande, mais avant cela, voyons comment nous pourrions nettoyer automatiquement les fichiers générés.
Nettoyer automatiquement les fichiers générés
Comme nous générons des fichiers de manière automatique, nous voulons nous assurer que les fichiers inutiles ne traînent pas quelque part. C’est ce qu’on appelle le nettoyage (ou plus simplement la suppression de fichiers).
On utilise le plugin del (delete) pour ce nettoyage.
npm install del --save-dev
puis :
//JS
var del = require('del');
La fonction del
prend un tableau (array) de globs Node qui lui indiquent les dossiers à supprimer.
C’est une tâche à peu près aussi simple que notre “hello” initial :
//JS
gulp.task('clean', function() {
del('dist');
})
Voilà, maintenant Gulp supprimera le dossier dist
à chaque fois que vous lancerez la tâche clean
(nettoyer).
Cependant, comme nous l’avons déjà dit, nous voulons éviter d’avoir à relancer la tâche images
car elle prend beaucoup de temps. Nous allons créer une tâche de nettoyage distincte, que nous utiliserons lorsque nous voulons tout nettoyer sauf les images dans dist
.
//JS
gulp.task('clean:dist', function(callback){
del(['dist/**/*', '!dist/images', '!dist/images/**/*'], callback)
});
Tout d’abord, nous supprimons tous les fichiers situés dans dist/**/*
. Toutefois nous ne voulons pas supprimer dist/images
, d’où l’identifiant !
devant dist/images
. De plus, nous ne voulons pas supprimer quoi que ce soit à l’intérieur de dist/images
, d’où le troisième glob !dist/images/**/*
.
Enfin, si nous voulons savoir quand la tâche clean:dist
est achevée, nous devons fournir un argument de callback.
Par exemple, dans la tâche clean
standard, nous allons nous assurer que le cache de Gulp est effacé afin de pouvoir optimiser à nouveau toutes nos images.
//JS
gulp.task('clean', function(callback) {
del('dist');
return cache.clearAll(callback);
})
Et maintenant, combinons toutes nos tâches !
Combiner les tâches Gulp
Résumons : jusqu’ici, nous avons créé deux ensembles distincts de tâches Gulp.
Le premier est un process de développement dans lequel nous compilons Sass en CSS, nous observons les modifications et nous rafraîchissons le navigateur en fonction des changements.
Le deuxième est un process d’optimisation grâce auquel nos fichiers sont prêts pour la production. Nous avons optimisé des fichiers CSS, JavaScript, images et nous avons copié nos fonts depuis app
vers dist
.
Nous avons déjà regroupé le premier ensemble de tâches dans un workflow simple avec la commande gulp watch
:
//JS
gulp.task('watch', ['browserSync', 'sass'], function (){
// ... watchers
})
Le deuxième ensemble est constitué de tâches que nous devons lancer pour créer le site en production. Parmi elles, clean:dist
, sass
, useref
, images
et fonts
.
Dans le même ordre d’idées, nous pourrions créer une tâche build
qui enchaînerait tout cela :
//JS
gulp.task('build', ['clean', 'sass', 'useref', 'images', 'fonts'], function (){
console.log('Building files');
})
Malheureusement, nous ne pouvons pas écrire ainsi la tâche build
car Gulp active simultanément toutes les tâches comprises dans le second argument. On pourrait imaginer que useref
, images
ou même fonts
soient achevées avant clean
, ce qui aurait pour conséquence que le dossier dist
serait supprimé.
Pour assurer un bon ordre des tâches, nous devons utiliser le plugin Run Sequence.
$ npm install run-sequence --save-dev
Voici la syntaxe d’une suite de tâches réalisées avec Run Sequence :
//JS
var runSequence = require('run-sequence');
gulp.task('nom-de-la-tache', function(callback) {
runSequence('tache1', 'tache2', 'tache3', callback);
});
Lorsque nom-de-la-tache
est appelée, Gulp lance d’abord la tache1
. Lorsque celle-ci est achevée, Gulp lance automatiquement la tache2
et, quand celle-ci est terminée, la tache3
.
Run Sequence vous permet également de lancer plusieurs tâches simultanément si vous les placez dans un array :
//JS
gulp.task('nom-de-la-tache', function(callback) {
runSequence('tache1', ['tache2','en','parallele'], 'tache3', callback);
});
Dans ce cas, Gulp lance d’abord tache1
. Lorsque celle-ci est achevée, Gulp lance toutes les tâches du second argument simultanément (tache2
, en
, et parallele
), et c’est seulement lorsque toutes ces tâches sont terminées qu’il lancera finalement la tache3
.
Donc, nous pouvons maintenant créer une tâche qui nous garantit que clean:dist
sera lancé d’abord, suivi des autres tâches.
//JS
gulp.task('build', function (callback) {
runSequence('clean:dist',
['sass', 'useref', 'images', 'fonts'],
callback
)
})
Pour la cohérence, nous pouvons construire la même séquence avec le premier groupe. Appelons cette tâche default
:
//JS
gulp.task('default', function (callback) {
runSequence(['sass','browserSync', 'watch'],
callback
)
})
Pourquoi default
? parce que lorsqu’une tâche s’appelle default, il suffit de taper gulp
dans la console, c’est une économie de temps.
Vous pouvez retrouver tout le travail que nous venons de réaliser sur ce repo github.
Récapitulation
Nous avons passé en revue les bases de Gulp et créé un workflow nous permettant de compiler Sass en CSS tout en suivant les modifications de fichiers HTML et JS. Nous pouvons lancer cette tâche via la commande gulp
dans la console.
Nous avons construit une deuxième tâche, build
, qui crée un dossier dist
pour le site en production. Nous avons compilé Sass en CSS, optimisé nos ressources et copié les fichiers nécessaires dans le dossier dist
. Pour lancer cette tâche, il nous suffit de taper gulp build
dans la console.
Enfin, nous avons une tâche clean
qui supprime du dossier dist
tous les caches d’images créées, ce qui nous permet de supprimer les vieux fichiers que nous aurions laissés dans dist
par inadvertance.
Nous avons créé un workflow robuste qui sera suffisant pour la plupart des développeurs web. Il y a bien sûr beaucoup d’autres choses dans Gulp et bien d’autres workflows que nous pouvons explorer pour améliorer encore ce process. Voici quelques idées :
Pour le développement :
- Utiliser Autoprefixer pour écrire un CSS sans se soucier des préfixes constructeurs ( NdT : voir ici même l’article sur Autoprefixer)
- Ajouter des sourcemaps pour faciliter le débogage
- Créer des sprites avec sprity
- Compiler uniquement les fichiers qui ont changé avec gulp-changed
- Écrire en ES6 avec Babel ou Traceur
- Modulariser les fichiers JavaScript avec Browserify, webpack ou jspm
- Modulariser HTML via les moteurs de templates Handlebars ou Swig
- Éclater le fichier gulpfile en plusieurs fichiers avec require-dir
- Générer automatiquement un script Modernizr avec gulp-modernizr
Pour l’optimisation :
- Supprimer le CSS non utilisé avec unCSS
- Optimiser plus encore les fichiers CSS avec gulp-csso (voir les explications dans la documentation)
- Générer du CSS en ligne pour améliorer la performance du site avec Critical
Par ailleurs, vous pouvez ajouter des unités de tests JS avec gulp-jasmine et même déployer automatiquement votre dossier dist
vers votre serveur de production via gulp-rsync.
Comme vous le voyez, même si notre workflow fait déjà pas mal de choses, il y a encore de la marge pour faire bien plus. C’est pourquoi j’ai écrit un livre sur l’automatisation de votre workflow et je vous invite à en télécharger 10 chapitres gratuitement si vous êtes intéressés. Vous pouvez également me contacter, je serai heureux de vous répondre !
(publicité)
Intéressé par les outils de développement ? Retrouvez une liste des meilleurs articles et ressources du web.
Tous les articles sur les workflows parus dans la Cascade.
Du même auteur dans La Cascade :
Articles sur les mêmes thèmes dans la Cascade :
- Grunt pour ceux qui pensent que Grunt est compliqué, par Chris Coyier
- La console, une introduction, par John Long
Ressources complémentaires en français
- Apprendre Gulp (créer un projet avec Browserify)
- Gulp, tutoriel vidéo par Grafikart
Ressources complémentaires en anglais
- Learning Gulp, une série de vidéos de Leveluptuts, excellentes comme toujours
- Combining Pattern Lab with Gulp for Improved Workflow, de Tim Hartman, combine l’automatisation du workflow et l’utilisation de guides de styles (Pattern Lab, basé sur le design atomique de Brad Frost présenté dans La Cascade)
(publicité)
Traduit avec l’aimable autorisation de CSS-Tricks et de l’auteur.
Copyright CSS-Tricks © 2015.
Sur l’auteur : Zell Liew est développeur et designer, il s’est formé lui-même à l’âge de 25 ans. On peut le suivre sur Twitter et sur son blog.