Utiliser Gulp en production Front-end (suite)

Attention ! Cet article a plus de 1 an (622 jours), ce qui signifie qu'il n'est pas forcément à jour !

Cet article est la suite de Utiliser Gulp en production Front-end

Sans plus attendre voici les parties de mon Gulpfile.js (je dis les parties, car je vais expliquer chacune des parties)

var gulp = require('gulp'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    gutil = require('gulp-util'),
    newer = require('gulp-newer'),
    imagemin = require('gulp-imagemin'),
    pngquant = require('imagemin-pngquant'),
    sass = require('gulp-sass'),
    sourcemaps = require('gulp-sourcemaps'),
    minifyCss = require('gulp-minify-css'),
    notify = require("gulp-notify"),
    bower = require('gulp-bower'),
    livereload = require('gulp-livereload'),
    connect = require('gulp-connect'),
    beep = require('beepbeep'),
    plumber = require('gulp-plumber'),
    browserSync = require('browser-sync'),
    reload      = browserSync.reload,
    autoprefixer = require('gulp-autoprefixer');

var onError = function (err) { beep([0, 0, 0]); gutil.log(gutil.colors.green(err)); };

var config_gulp = require('./config_gulp.js')

var config = {
  bowerDir: './assets_dev/vendor'
};

var paths = {
  src: 'assets_dev',
  dest: 'assets_dist',
  jssrc: 'assets_dev/js/**/[_]*.js',
  csss: 'assets_dev/css/**/*.scss',
  imgSrc: 'assets_dev/img/**/*',
  imgDest: 'assets_dist/img',
  htmlSources : '**/*.html'
};

Tout d’abord, on charge tous les modules et on les assigne à des variables.

Je me crée ensuite une variable onError, qui vient surcharger la variable par défaut. Ce qui va faire que, lors d’une erreur, 3 bips sonores vont se faire entendre et une erreur détaillée va s’afficher dans la console.

Je charge ensuite mon fichier de config, j’informe du dossier pour le Bower et finalement je crée un objet avec les différentes variables de chemin.

Trois premières tâches

//Tâche pour le bower
gulp.task('bower', function() {
    return bower({ cmd: 'update' })
      .pipe(gulp.dest(config.bowerDir))
});

//Tâche qui copie les fonts suite à la fonction bower et les mets dans le DIST
gulp.task('copy', ['bower'], function() {
  migration = config_gulp.migrationConfig;
  for (var key in migration) {
    if (migration.hasOwnProperty(key)) {
      gulp.src([key])
       .pipe(gulp.dest( migration[key]));
    }
  }
});

gulp.task('copyfonts', function() {
  return gulp.src(['./assets_dev/fonts/**/*'])
      .pipe(newer('./assets_dev/fonts/**/*'))
      .pipe(gulp.dest('./assets_dist/fonts'))
      .pipe(reload({stream: true}));
});

La première tâche que je vais effectuer est la mise à jour du Bower. Comme Bootstrap est chargé par le bower et que nous allons utiliser ses fichiers CSS par la suite, on doit s’assurer que le Bower a bien été complété.

Ensuite la seconde tâche est celle qui copie la liste de fichiers que l’on voulait transférer manuellement (celle qui est dans le config_gulp.js) C’est donc là que l’on peut décider d’envoyer dans notre dossier de production tous les fichiers nécessaires qui ne sont pas nécessairement des css, js, etc. Disons, par exemple, des fichiers json, des fichiers de configs, des XML, etc.

La troisième tâche copie toutes les polices d’écriture qu’il y a dans notre dossier fonts et les envoie en production.

La suite avec le JS

//Tâche concat et uglify le JS
gulp.task('concat_Build', function() {
  return gulp.src(paths.jssrc)
    .pipe(plumber({ errorHandler: onError }))
    .pipe(uglify())
    .pipe(concat('main.js'))
    .pipe(gulp.dest('./assets_dist/js'));
});

//Tâche concat le JS
gulp.task('concat', function() {
  return gulp.src(paths.jssrc)
    .pipe(newer(paths.jssrc))
    .pipe(sourcemaps.init())
    .pipe(plumber({ errorHandler: onError }))
    .pipe(concat('main.js'))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('./assets_dist/js'))
    .pipe(reload({stream: true}));
});

//Tâche qui concat les Vendors
//TODO rendre les src du vendor dynamique
gulp.task('concat_Vendor', function() {
  return gulp.src(config_gulp.vendorConfig)
    .pipe(sourcemaps.init())
    .pipe(concat('vendor.js'))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('./assets_dist/js'));
});

Les tâches concat_build et concat sont assez semblables. La première va être effectuée seulement avec notre tâche principale pour faire un "build" pour la production finale. Tout est compressé avec la function uglify(). Tandis que la tâche concat, va conserver un JS propre et compréhensible, et créer un sourcemap. Le fichier main.js qui va en résulter va donc être plus facile à lire durant notre phase de développement. La dernière tâche va chercher dans notre fichier gulp_config tous les JS que l’on voulait mettre dans le vendor.js.

Les images

//Tâche qui compresse les images
gulp.task('img', function() {
  return gulp.src(paths.imgSrc)
    .pipe(newer(paths.imgDest))
    .pipe(imagemin({
      progressive: true,
      svgoPlugins: [{removeViewBox: false}],
      use: [pngquant()]
    }))
        .pipe(gulp.dest(paths.imgDest))
        .pipe(reload({stream: true}));
});

Cette tâche va prendre toutes les images du dossier img, les compresser et les déposer dans notre /assets_dist/img/.

Le CSS

//Tâche qui SASS les CSS
gulp.task('sass', function () {
  gulp.src('./assets_dev/css/**/*.scss')
    .pipe(sourcemaps.init())
    .pipe(newer(paths.csss))
    .pipe(plumber({ errorHandler: onError }))
    .pipe(sass())
    .pipe(sourcemaps.write({includeContent: false}))
    .pipe(sourcemaps.init({loadMaps: true}))
    .pipe(autoprefixer())
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./assets_dist/css'))
    .pipe(reload({stream: true}));
});

//Tâche qui SASS et minify les CSS
gulp.task('sass_Build', function () {
  gulp.src('./assets_dev/css/**/*.scss')
    .pipe(plumber({ errorHandler: onError }))
    .pipe(sass())
    .pipe(autoprefixer())
    .pipe(minifyCss())
    .pipe(gulp.dest('./assets_dist/css'))
});

Encore une fois deux tâches qui font sensiblement la même chose, l’une pour la phase de développement et l’autre quand on veut faire un "build" final pour la production. Le premier génère en même temps que le fichier main.css un fichier de sourcemap qui est très pratique avec la console de débug de Chrome. En fait c’est grâce à ce fichier que lorsque l’on inspecte un élément dans la console de Chrome, il va nous dire exactement dans lequel des fichiers SCSS source provient ce style.

J’utilise aussi la fonction autoprefixer(). Ce magnifique outil, basé sur CanIUse.com, permet de préfixer automatiquement vos CSS, et ce, de manière intelligente. Vous pouvez en effet configurer autoprefixer, afin de lui préciser quel navigateur vous voulez utiliser. Vous pouvez au choix lui demander de supporter X versions en arrière, les versions qui ont un usage global > à Y% de trafic, ou encore une version minimale donnée.

Ensuite Brower-sync

gulp.task('browser-sync', function() {
    browserSync.init({
        server: {
            baseDir: "./"
        }
    });
});

//Tâche qui livereload les HTML
gulp.task('html', function() {
  gulp.src(paths.htmlSources)
  .pipe(reload({stream: true}));
});

Brower-sync est un module pour nodeJS qui va vous permettre d’actualiser et de synchroniser automatiquement vos pages web pour un développement plus rapide. Il va donc vous permettre de sauvegarder votre SCSS, il va reloader votre page HTML automatiquement et on peut l’utiliser pour synchroniser plusieurs navigateurs et même tester en live les versions sur mobile et tablette (il faudra en revanche être sur le même réseau local) (Oui oui, vous allez "scroller" sur l’un ça va le faire sur les autres.) Il permet aussi d’avoir une console (assez simple) sur chacun de ces navigateurs et appareils. (Pouvoir enfin avoir une console quand on doit débugger une version iPhone et que l’on est sur un PC.)

La finale

// Tâche qui watch le js et le css
gulp.task('watch', function() {
  gulp.watch(paths.jssrc, ['concat']);
  gulp.watch(paths.imgSrc, ['img']);
  gulp.watch(paths.csss, ['sass']);
  migration = config_gulp.migrationConfig;
    for (var key in migration) {
      if (migration.hasOwnProperty(key)) {
        gulp.watch([key], ['copy']);
      }
    }
});

// Tâche DEFAULT
gulp.task('default', ['html', 'browser-sync', 'watch', 'concat_Vendor', 'sass', 'concat', 'copy', 'copyfonts', 'img']);
// Tâche START, première tâche à effectuer
gulp.task('start', ['bower']);
// Tâche BUILD
gulp.task('build', ['copy', 'copyfonts', 'sass_Build', 'concat_Vendor', 'concat_Build', 'img']);

La tâche watch vérifie s’il y a des changements apportés dans vos dossiers d’images, votre CSS ou votre JS et effectue les tâches associées.

Ensuite, les tâches principales qui effectuent toutes les tâches secondaires sont énumérées. Donc trois tâches gulp, gulp start et gulp build

La vrai grande finale

Pour que le tout fonctionne on doit s’assurer d’avoir NodeJS d’installé. Voir Débuter avec Gulp au besoin.

On doit aussi avoir gulp et Bower d’installés de manière globale. Pour ce faire on fait ces commandes dans la console.

npm install gulp -g
npm install bower -g

Dans le terminal, on peut ensuite aller à notre dossier et faire la commande

npm install

Ceci va installer les modules nécessaires. C’est quelques fois un peu long, certains modules le sont plus que d’autres.

Une fois terminé vous faîtes :

gulp start 

Ceci va télécharger nos dépendances par le Bower.

Et voilà, vous faites :

gulp 

Et le tour est joué!! Gulp va continuellement rouler en attente de modification de css, js, ou d’images.

Une fois la production terminée, je conseille de faire un

gulp build

pour avoir des fichiers minifiés à envoyer en production.

Bon code!!!

Catégories :

HTML CSS Javascript