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 !
1 De saymonz -
Dis, j’y connais rien à ce genre d’outils en dehors de tes billets à ce sujet, mais s’il faut 100+ lignes de fichiers de “configuration” pour “juste” compilation / minification / compression d’une extension, quelle est la valeur ajoutée par gulp par rapport à un script batch ou python (ou même PHP d’ailleurs) qui pourrait probablement être sensiblement plus court ?
2 De Franck -
L’avantage le plus clair, pour moi, est que tu n’as pas à te soucier des outils qui compilent/transpilent/minifient/compressent (c’est géré par les plugins).
J’aurais tout aussi pu continuer avec les scripts bash qui font appel à du code PHP ou autre, sauf qu’il y a des étapes qui ne sont pas automatisées, pour l’instant : compilation sass par exemple.
Avec Gulp (ou consort) c’est un peu plus intégré.
Cela dit je découvre, hein ? Je dis peut-être des grosses conneries :-)
3 De JcDenis -
Tu veux que je fasse un plugin Dotclear qui compile un plugin/théme Dotclear ? … … … J’suis plus là :p
Plus sérieusement, je suis très vieux jeux, j’ai du mal avec le fait d’utiliser un outil embarquant de quoi faire la 3eme guerre mondiale, juste pour faire un fichier CSS. J’ai arrêté quand Composer & Co sont apparus. Même si j’ai tord, m’en fout, j’suis vieux.
4 De Franck -
JcDenis hi hi, moi j’suis jeune, donc je suis obligé d’utiliser des trucs modernes, tu comprends :-)
Sérieusement, j’aimerais bien avoir un truc tout intégré pour gérer tous les trucs chiants de dév d’un thème, plugin, voire de Dotclear (on peut toujours rêver) ; cela dit jusque là j’utilisais (et j’utilise toujours) avec bonheur la ligne de commande (sass/compass) et ton pacKman ;-)
5 De saymonz -
Pas convaincu par l’argument, je dois être vieux aussi 😋
Qu’est-ce qui t’empêche d’intégrer la compilation SASS à un script maison par exemple ? Ils semblent fournir un binaire (le même qui sera utilisé par Gulp je suppose) dont l’utilisation ne devrait pas être moins stable et prédictible amha… Je présume qu’il en est de même pour les différents outils.
Je rejoins JCDenis sur l’impression que tu attaques les mouches au bazooka. Je peux tout à fait comprendre l’attrait d’un nouveau jouet pour geek par contre, et c’est une raison suffisante en soi 😉 !
6 De Franck -
Rien ne m’empêche d’intégrer la compilation Sass à un script maison, évidemment, sauf que ça veut dire qu’il faut que celui qui utilise le script ait pris soin d’installer Sass sur sa machine. Jusque là, spa trop compliqué, mais multiplié par le nombre d’outils potentiellement utilisés (minifier, …), ça peut devenir pénible plutôt que d’utiliser un
npm i
… qui impose l’installation préalable de Node :-DLa boucle est bouclée, hi hi.
Cela dit je suppose plus facile la maintenance d’un environnement Gulp/Node local et du script qui définit les différentes tâches disponibles.
Mais je peux me tromper.
Et c’est vrai, j’aime bien essayer de nouveaux trucs — et ça dure depuis plus de 40 ans que je pose mes doigts sur un clavier —, on se refait pas, hein ?