Automatiser la compilation frontend avec Gulp 4

Gulp 4 est un outil de construction orienté flux qui permet d’orchestrer efficacement des tâches de transformation sur les ressources statiques — HTML, CSS et JavaScript — sans nécessiter de configuraton complexe ni de gestion de modules natifs. Bien qu’il ne gère pas le bundling avancé comme Webpack, sa modularité via des plugins rend possible une chaîne de compilation robuste pour des projets légers ou intermédiaires.

Optimisation HTML avec html-minifier

Pour réduire la taille des fichiers HTML tout en préservant leur structure, on utilise gulp-html-minifier-terser, une version mise à jour et maintenue du classique gulp-htmlmin.

const { src, dest } = require('gulp');
const htmlMinifier = require('gulp-html-minifier-terser');

function optimizeHtml() {
  return src('src/**/*.html', { base: 'src' })
    .pipe(htmlMinifier({
      collapseWhitespace: true,
      removeComments: true,
      minifyCSS: true,
      minifyJS: true
    }))
    .pipe(dest('build'));
}

exports.optimizeHtml = optimizeHtml;

Compilation LESS et post-traitement CSS

La transformation LESS vers CSS s’effectue via gulp-less. Pour garantir la compatibilité navigateur, on injecte postcss avec autoprefixer et cssnano, plutôt que postcss-preset-env, afin d’obtenir un contrôle plus fin sur les fonctionnalités ciblées.

const less = require('gulp-less');
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');

function compileStyles() {
  return src('src/styles/**/*.less', { base: 'src' })
    .pipe(less())
    .pipe(postcss([
      autoprefixer({ overrideBrowserslist: ['> 1%', 'last 2 versions'] }),
      cssnano({ preset: 'default' })
    ]))
    .pipe(dest('build'));
}

exports.compileStyles = compileStyles;

Transformation et minification JavaScript

Le transpilage ES2020+ vers ES5 se fait avec @babel/core et gulp-babel, tandis que la minification repose sur gulp-terser avec des options personnalisées pour préserver les noms de varialbes critiques.

const babel = require('gulp-babel');
const terser = require('gulp-terser');

function transpileScripts() {
  return src('src/scripts/**/*.js', { base: 'src' })
    .pipe(babel({
      presets: [
        ['@babel/preset-env', { targets: { browsers: ['> 1%'] } }]
      ]
    }))
    .pipe(terser({
      compress: { drop_console: true, drop_debugger: true },
      mangle: { reserved: ['jQuery', '$'] }
    }))
    .pipe(dest('build'));
}

exports.transpileScripts = transpileScripts;

Injection dynamique des ressources dans HTML

Au lieu d’insérer manuellement les liens CSS ou scripts, gulp-inject automatise l’injection en détectant les balises spécifiques dans les templates HTML — par exemple \<!-- inject:css --> et <!-- inject:js -->.

const inject = require('gulp-inject');

function injectAssets() {
  return src('build/index.html')
    .pipe(inject(
      src(['build/styles/**/*.css', 'build/scripts/**/*.js'], { read: false }),
      {
        transform: (filePath) => {
          const file = filePath.replace('build/', '');
          if (file.endsWith('.css')) {
            return `<link href="${file}" rel="stylesheet"></link>`;
          }
          if (file.endsWith('.js')) {
            return `<script src="${file}"></script>`;
          }
        }
      }
    ))
    .pipe(dest('build'));
}

exports.injectAssets = injectAssets;

Reloading automatique avec BrowserSync

En combinaison avec watch, browser-sync surveille les modifications dans src/ et déclenche les tâches correspondantes, puis rafraîchit automatiquement le navigateur.

const browserSync = require('browser-sync').create();

function startServer() {
  browserSync.init({
    server: { baseDir: 'build' },
    port: 3000,
    open: true,
    notify: false
  });

  watch('src/**/*.html', gulp.series(optimizeHtml, injectAssets)).on('change', browserSync.reload);
  watch('src/styles/**/*.less', gulp.series(compileStyles, injectAssets)).on('change', browserSync.reload);
  watch('src/scripts/**/*.js', gulp.series(transpileScripts, injectAssets)).on('change', browserSync.reload);
}

exports.serve = startServer;

Orchestration de tâches avec series et parallel

Pour simplifier l’exécution, on regroupe les opérations : les compilations HTML, CSS et JS s’exécutent en parallèle, suivies d’une injection unique ; le serveur démarre ensuite après la première génération complète.

const { series, parallel } = require('gulp');

const build = series(
  parallel(optimizeHtml, compileStyles, transpileScripts),
  injectAssets
);

const dev = series(build, startServer);

exports.build = build;
exports.default = dev;

Dans package.json, on peut définir :

"scripts": {
  "build": "gulp build",
  "start": "gulp"
}

Étiquettes: gulp4 less PostCSS babel terser

Publié le 30 juillet à 07h17