Gulp, retour d'expérience

Motobécane, Guilvinec, France, juil. 2012
Motobécane

Eh bien après avoir testé Parcel et Webpack et failli laisser de côté Gulp — j’ai volontairement fait l’impasse sur le vieillissant Grunt — j’ai passé la journée d’hier à voir comment mettre ça en place et j’en suis arrivé à bout !

Production des fichiers CSS — éventuellement compilés depuis les sources Sass — et JS minifiés, jusqu’à la production d’une archive d’un thème (ou d’un plugin) installable directement avec Dotclear, c’est finalement ce système qui m’a posé le moins de problèmes.

Résultat des courses, j’opte pour Gulp que je vais bientôt tester sur un plugin, pour voir ce que je peux encore généraliser.

En attendant, appliqué au thème Ensemble en cours de développement, ça donne ceci :

Tout d’abord le fichier package.json :

{
  "name": "ensemble",
  "version": "1.0",
  "description": "Dotclear 2 theme",
  "module": "theme",
  "devDependencies": {
    "dart-sass": "^1.25.0",
    "del": "^6.0.0",
    "gulp": "^4.0.2",
    "gulp-clean-css": "^4.3.0",
    "gulp-mode": "^1.0.2",
    "gulp-plumber": "^1.2.1",
    "gulp-sass": "^4.1.0",
    "gulp-sourcemaps": "^3.0.0",
    "gulp-uglify": "^3.0.2",
    "gulp-zip": "^5.1.0"
  },
  "scripts": {
    "clean": "gulp clean",
    "build": "gulp build",
    "pack": "export NODE_ENV=production && gulp clean && gulp build && gulp pack"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/franck-paul/ensemble.git"
  },
  "author": "Franck Paul and contributors",
  "license": "GPL-2.0",
  "bugs": {
    "url": "https://github.com/franck-paul/ensemble/issues"
  },
  "homepage": "https://github.com/franck-paul/ensemble#readme"
}

Puis le fichier gulpfile.js :

'use strict';

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

const plg_sass = require('gulp-sass');
const plg_cleanCSS = require('gulp-clean-css');
const plg_sourcemaps = require('gulp-sourcemaps');
const plg_uglify = require('gulp-uglify');

plg_sass.compiler = require('dart-sass');

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

const del = require('del');
const zip = require('gulp-zip');

const pjson = require('./package.json');

// Assets
const assets = {
  css: 'src/css/*.css',
  sass: 'src/scss/main.scss',
  js: 'src/js/*.js',
  font: ['src/css/fonts/**.*', 'src/scss/fonts/**.*'],
};

// Paths
const paths = {
  dist: 'dist',
  pack: 'package'
};

// Package elements
const elements = ['*.php', 'LICENSE', 'README.md', 'tpl/*', 'dist/*', '!dist/*.map'];

// Sass
const sass = function (done) {
  gulp
    .src(assets.sass)
    .pipe(mode.development(plg_sourcemaps.init()))
    .pipe(plg_sass()) // Converts Sass to CSS with gulp-sass
    .pipe(mode.production(plg_cleanCSS()))
    .pipe(mode.development(plg_sourcemaps.write('.')))
    .pipe(gulp.dest(paths.dist));
  done();
};
exports.do_sass = series(sass);

// CSS
const css = function (done) {
  gulp
    .src(assets.css)
    .pipe(mode.development(plg_sourcemaps.init()))
    .pipe(mode.production(plg_cleanCSS()))
    .pipe(mode.development(plg_sourcemaps.write('.')))
    .pipe(gulp.dest(paths.dist));
  done();
};
exports.do_css = series(css);

// Js
const js = function (done) {
  gulp
    .src(assets.js)
    .pipe(mode.development(plg_sourcemaps.init()))
    .pipe(mode.production(plg_uglify())) // Minify JS files
    .pipe(mode.development(plg_sourcemaps.write('.')))
    .pipe(gulp.dest(paths.dist));
  done();
};
exports.do_js = series(js);

// Fonts
const fonts = function (done) {
  gulp
    .src(assets.font)
    .pipe(gulp.dest(paths.dist + '/fonts'));
  done();
};
exports.do_fonts = series(fonts);

// Cleanup
const clean = function (done) {
  del('./' + paths.dist);
  done();
};
exports.clean = series(clean);

// Build
exports.build = series(clean, parallel(css, sass, js, fonts));

// Watch
exports.watch = function () {
  watch(assets.sass, sass);
  watch(assets.css, css);
  watch(assets.js, js);
  watch(assets.font, fonts);
};

// Package build
const pack = function (done) {
  gulp
    .src(elements, { base: '.' })
    .pipe(gulp.dest(pjson.module + '-' + pjson.name + '-' + pjson.version + '/' + pjson.name))
    .pipe(zip(pjson.module + '-' + pjson.name + '-' + pjson.version + '.zip'))
    .pipe(gulp.dest(paths.pack));
  del('./' + pjson.module + '-' + pjson.name + '-' + pjson.version);
  done();
};
exports.pack = series(pack);

J’ai essayé de rendre ça le plus simple à paramétrer en choisissant une structure de répertoire plutôt commune :

  • src : fichiers sources CSS, JS et Sass, chacun dans leur sous-répertoire respectif css, scss et js ; j’ai aussi prévu l’éventuelle présence de fichiers de police de caractères dans un sous-répertoire fonts des répertoires css et scss. Il faudra éventuellement que je complète pour les images utilisées dans les feuilles de style.
  • dist : accueille tous les fichiers CSS/JS compilés/minifiés et les éventuels fichier .map
  • package : accueille l’archive du thème (ou du plugin) une fois celle-ci générée

Le reste est standard. Côté plugin il faudra surement adapter un peu, à voir au fur et à mesure.

J’ai rencontré un problème avec l’utilisation du module node del qui supprime ce qu’on lui demande une fois sur deux ?!?

Par ailleurs j’ai été obligé de forcer l’usage du module dart-sass plutôt que le node-sass standard utilisé par gulp-sass parce que l’expression suivante provoque une erreur avec ce dernier :

img {
  /* 2em is for body left + right margin */
  max-width: min(58em, calc(100vw - 2em));
}

Avec node-sass il m’engueule en me disant que les unités vw et em ne sont pas compatibles dans une expression calc(…) !

Voili, voilà

Pour conclure, Gulp reste, de mon point de vue tout à fait subjectif, le plus simple à déployer et le plus souple à configurer.

PS : Si vous avez des billes sur mon problème de suppression qui fonctionne une fois sur deux avec del, j’suis preneur !

Ajouter un commentaire

Les commentaires peuvent être formatés en utilisant la syntaxe Markdown Extra.

Ajouter un rétrolien

URL de rétrolien : https://open-time.net/trackback/14937

Haut de page