Préambule : cet article part du principe que vous n’êtes pas totalement étranger aux notions et outils tels que LESS, NodeJS, Gulp ni à la ligne de commande, il ne s'agit d'un tutoriel de découverte de ces outils mais d'usage en environnement professionnel.
Introduction
Au sein de l’agence web Alsacreations.fr, nous avons instauré un processus de travail (un “workflow”) composé de langage LESS, compilé avec des tâches Gulp et saupoudré de conventions internes et de KNACSS.
Le site goetter.fr est mon site personnel, mon bac à sable et mon espace de test pour moults expériences web.
La version actuelle du site est très artisanale et manuelle. J’ai voulu tester la mise en place d’un workflow automatisé afin de profiter de toutes les tâches courantes (compilation LESS, minification, préfixes CSS automatiques, concaténation des fichiers JS, optimisation des images) tout en testant deux fonctionnalités intéressantes : les includes de fichiers en HTML ainsi que l’outil de perf web prôné par Google : “critical CSS”.
Cela m’a pris une journée de reprendre tout le workflow de mon site perso. Je vous la partage ici…
L’environnement Gulp
Dans la version précédente de mon site personnel, mon dossier de travail était le même que celui de production : je faisais simplement attention à ne pas mettre en prod les fichiers inutiles (CSS non minifié, images non optimisées) et j'employais le logiciel Prepros.io pour compiler mes fichiers.
Avec le choix de Gulp, mon processus de travail est aujourd'hui différent dans la mesure où je scinde deux environnements distincts :
-
tous mes fichiers en développement sont dans
_src/
-
les fichiers compilés, à envoyer en prod sont tous dans
_dist/
Gulp est un outil d'automatisation de tâches (un "task manager") basé sur nodeJS. Une fois NodeJS en place, Gulp s'installe en ligne de commande :
npm install gulp -g
Pour fonctionner, Gulp nécessite deux fichiers de travail :
-
package.json
(contient tous les plugins nécessaires aux tâches à éxécuter) -
gulpfile.js
(exécute les tâches)
Pour rappel, je ne prévois pas de rentrer dans les détails de ce que sont gulp, gulpfile.js
et package.json
car cet article n'est pas une introduction à ces outils. Si ces termes vous sont totalement étrangers, je vous invite à plonger dans l'article "Introduction à Gulp".
J’utilise à présent Gulp pour réaliser toutes mes tâches courantes (pas bien complexes mais souvent répétitives), et voici quels sont les plugins prévus au sein de mon fichier package.json
:
- “gulp”
- “gulp-less” (compilation LESS vers CSS)
- “gulp-autoprefixer” (ajout des préfixes nécessaires)
- “gulp-minify-css” (minification CSS)
- “gulp-rename” (renommage en “.min.css”)
- “gulp-uglify” (minification JS)
- “gulp-imagemin” (optimisation des images)
- “gulp-html-extend” (includes HTML)
- “gulp-uncss” (suppression des CSS non utilisés)
- “critical” (CSS inline)
Les tâches courantes
Toutes les tâches suivantes sont inclues dans mon fichier gulpfile.js
et exécutées sur demande ou automatiquement (watch
) en ligne de commande.
tâches CSS
- LESS
- autoprefixer
- minification
La tâche “css” du fichier gulpfile.js
:
// Tâche "css" = LESS + autoprefixer + minify
gulp.task('css', function() {
return gulp.src(source + '/assets/css/styles.less')
.pipe(less())
.pipe(autoprefixer())
.pipe(rename({
suffix: '.min'
}))
.pipe(minify())
.pipe(gulp.dest(prod + '/assets/css/'));
});
Explications : mon fichier de travail (styles.less
) est tout d'abord compilé en CSS classique, puis préfixé, puis renommé en .min.css
avant d'être minifié et placé dans mon dossier de production.
tâches JavaScript
- concaténation
- minification (uglify)
La tâche “js” du fichier gulpfile.js
:
// Tâche "js" = uglify + concat
gulp.task('js', function() {
return gulp.src(source + '/assets/js/*.js')
.pipe(uglify())
.pipe(concat('global.min.js'))
.pipe(gulp.dest(prod + '/assets/js/'));
});
Explications : tous les fichiers JavaScript du dossier /js/
sont minifiés pour concaténés (regroupés) en un seul fichier global.min.js
et placé dans mon dossier de production.
tâches d’optimisation d’images
- optimisation PNG, JPG, SVG
La tâche “img” du fichier gulpfile.js
:
// Tâche "img" = Images optimisées
gulp.task('img', function () {
return gulp.src(source + '/assets/img/*.{png,jpg,jpeg,gif,svg}')
.pipe(imagemin())
.pipe(gulp.dest(prod + '/assets/img'));
});
unCSS pour alléger les fichiers
unCSS est un outil (disponible en versions grunt et gulp) permettant de supprimer les styles CSS non utilisés au sein de votre projet.
Il s'agit d'une véritable bénédiction lorsque vous travaillez à l'aide de frameworks CSS tels que Bootstrap ou KNACSS car il va réduire drastiquement le poids de vos fichiers CSS :
If you're building a #twitterbootstrap page with #grunt or #gulp, consider using #uncss. > CSS file reduced from 150kB to 11kB! #Javascript
— Sascha Sambale (@mastixmc) 11 Mars 2015
unCSS fonctionne bien évidemment sur un ensemble de fichiers et fait très bien son boulot... à condition que vous n'ayez oublié aucun fichier dans la boucle !
Sur le site de goetter.fr, la feuille de style CSS minifiée est passée de 16ko à 10ko après l'action de unCSS, soit une réduction de 40%. Imaginez le résultat sur des gros fichiers de centaines de ko. Le pire est que le site fonctionne toujours, rien n'est cassé :)
unCSS a été intégrée dans ma tâche "css" ainsi :
// Tâche "css" = LESS + autoprefixer + unCSS + minify
gulp.task('css', function() {
return gulp.src(source + '/assets/css/*.less')
.pipe(less())
.pipe(autoprefixer())
.pipe(uncss({
html: [source + '/{,_includes/}/{,conf/}/{,livres/}*.html']
}))
.pipe(rename({
suffix: '.min'
}))
.pipe(minify())
.pipe(gulp.dest(prod + '/assets/css/'));
});
Explications : tous les fichiers HTML à la racine du site ainsi que ceux situés dans les dossiers /conf
, /livres
et /_include
seront testés par un navigateur fantôme. Tous les styles qui ne sont pas utilises au sein de ces fichiers sont supprimés.
Attentions aux classes "dynamiques" !
unCSS fonctionne tel un navigateur fantôme qui parcourt votre page web à un instant T. Il ne peut pas deviner si JavaScript actionne ou ajoute des classes CSS dans votre DOM. Ces classes dynamiques seront donc invisibles pour lui et il va les supprimer.
C'est ce qui est arrivé sur ma navigation: la classe .is-closed
est activée via JavaScript. Du coup unCSS supprime un classe importante de mes styles ([id="main"]:not(.is-closed)
), rendant mon menu de navigation inopérationel.
Pour corriger ce problème, il est parfaitement possible d'insérer un paramètre ignore
au sein de la tâche Gulp afin de préserver les classes d'une éventuelle suppression :
gulp.task('css', function() {
return gulp.src(source + '/assets/css/*.less')
...
.pipe(uncss({
html: [source + '/{,_includes/}/{,conf/}/{,livres/}*.html'],
ignore: ['[id="main"]:not(.is-closed)']
}))
...
});
Des includes en HTML
Passons à présent à des tâches moins classiques, voire carrément spécifiques à mes besoins et envies.
En tant qu'intégrateur HTML/CSS, j’ai toujours été quelque peu frustré de devoir passer par un langage serveur pour faire des inclusions de fichiers partiels (header, footer, nav, etc.).
Bien-sûr, il est possible de passer par JavaScript, AJAX, webcomponents / polymer ou des langages tels Jade, HAML ou Handlebars pour atteindre cet objectif, mais en toute honnêteté je ne suis pas fan de rajouter une couche de complexité à mon workflow et je ne supporte pas les syntaxes “à la Jade”.
Je veux écrire du bête HTML et avoir des include de fichiers. Je veux le beurre et l’argent du beurre. Et là, sur mon site perso, je peux me le permettre.
Par chance, puisque mon workflow est déjà basé sur NodeJS / Gulp, il existe des plugins pour parvenir à mes fins.
L’un de ces plugins est “Gulp HTML extend”.
À l’aide de simples commentaires HTML, il offre (au-moins) deux fonctionnalités qui m’intéressent tout particulièrement :
- les inclusions de fichiers partiels
- l’utilisation de variables
Le principe est simplissime : les instructions se présentent sous forme de commentaires HTML (pour préserver la syntaxe et la validité), par exemple <!-- @@include fichier.txt -->
pour inclure un fichier dans le document, ou bien <!-- @@var variable -->
pour inclure une variable.
Voici un exemple de page index.html
avant compilation :
<head>
<!-- @@include _includes/head.html {"title": "Mon site web personnel", "path": "../"} -->
</head>
Le fichier inclus head.html
:
<meta charset="UTF-8">
<title><!-- @@var title --></title>
...
<link rel="stylesheet" href="<!-- @@var path -->assets/css/styles.min.css" media="all">
Et le résultat compilé index.html
en prod :
<meta charset="UTF-8">
<title>Mon site web personnel</title>
...
<link rel="stylesheet" href="../assets/css/styles.min.css" media="all">
</head>
Voici la tâche “html” du fichier gulpfile.js
correspondant à mes besoins :
// Tâche "html" = includes HTML
gulp.task('html', function() {
return gulp.src(source + '/{,conf/}/{,livres/}*.html')
// Generates HTML includes
.pipe(extender({
annotations: false,
verbose: false
})) // default options
.pipe(gulp.dest(prod))
});
Explications : tous les fichiers HTML à la racine du site ainsi que ceux situés dans les dossiers /conf
et /livres
seront compilés en tenant compte des inclusions et des variables fournies.
La documentation et les options de ce plugin : https://www.npmjs.com/package/gulp-html-extend
Critical CSS
Autre plugin que j’ai pu mettre en place sur mon site perso : “Critical CSS”.
Vous avez déjà certainement été confronté à l’un des conseils récurrents de Google PageSpeed Insights (l’outil de perf web très pratique pour tester son site mobile et desktop) qui est Éliminer les codes JavaScript et CSS qui bloquent l’affichage du contenu au-dessus de la ligne de flottaison
.
L’explication est celle-ci : JavaScript et CSS retardent l’affichage de la page tant qu’ils ne sont pas chargés.
Google considère que la partie visible d’une page web, c’est à dire tout se qui se trouve au-dessus de la ligne de flottaison (ou “above the fold”), devrait être affiché instantanément, soit :
-
en différant ou en rendant les ressources asynchrones (
async
,defer
), -
soit en éliminant toutes les requêtes de styles CSS “critiques” (= ceux participant à l’affichage du design au dessus de la ligne de flottaison). Pour cela, la méthode est d’insérer ces CSS “critiques” directement dans la page HTML (on “inline” les CSS dans l’élément
<style>
comme au bon vieux temps des newsletter).
Sans surprise, la méthode d‘“inliner” les CSS dans l’élément <style>
présente un sacré paquet d’inconvénients (un peu les mêmes que l’on retrouve avec les data-URI
) :
- les fichiers HTML sont beaucoup plus lourds
- ils sont également moins lisibles et plus difficiles à maintenir
- c’est moche
La contrepartie est que les avantages... ne sont pas négligeables non plus :
- les résultats sont très probants en terme de performance d’affichage (des gains de parfois plusieurs secondes)
- de très gros sites comme The Guardian ont réussi à charger leur page d’accueil en moins de 1 seconde grâce à l’optimisation de leurs CSS “critiques”.
- il est possible d’automatiser ce processus
Quelques ressources intéressantes sur ce sujet qui ne l’est pas moins :
- “How we make RWD sites load fast as heck” (Filament Group, 2014)
- “Inlining critical CSS for first-time visits” (Adactio, 2015)
- “Breaking Development: Optimizing the Critical Rendering Path” (Luke Wroblewski, 2013)
Si vous ne deviez retenir qu’une seule ressource, je vous invite vivement à vous imprégner de la conférence de Patrick Hamann (The Guardian), “CSS and the critical path” dont voici les slides et la vidéo associée.
Critical CSS en pratique
Il existe deux outils connus et suffisamment maintenus et testés pour réaliser la tâche de “inliner des CSS” : Critical d’Addy Osmani et CriticalCSS de Filament Group. Les deux proposent une version Grunt et Gulp.
Pour ma part et sur mon site perso goetter.fr, j’ai utilisé le premier de ces deux outils, Critical, en version Gulp bien sûr.
Voici ma tâche “critical” du fichier gulpfile.js
:
// Tâche "critical" = critical inline CSS
gulp.task('critical', function() {
return gulp.src(prod + '/*.html')
.pipe(critical({
base: prod,
inline: true,
width: 320,
height: 480,
minify: true
}))
.pipe(gulp.dest(prod));
});
Le principe général est celui-ci :
- un navigateur fantôme parcourt la(es) page(s) concernée(s) dans les dimensions précisées (ici 320x480)
- il en déduit les CSS “critiques”, participant à l’affichage au dessus de la ligne de flottaison
-
il les extrait et les insère directement (minifiés) au sein d’une balise
<style>
dans la page - le “reste” de la feuille de style est chargée de manière asynchrone via JavaScript et LoadCSS
-
pour les navigateurs sans JS, la feuille de style est chargée au sein d’un
<noscript>
- et tout ça tout seul comme un grand !
Dans mon cas, j’ai décidé que seront concernés tous les fichiers à la racine du site (et uniquement ceux-là).
Critical : efficace ?
Maintenant que l’on s’est bien amusé, passons quelques tests pour découvrir si ça en valait vraiment la peine…
D’après Google PageSpeed Insights
Google PageSpeed Insights donne une “note globale de performance” sur 100 à votre page en version mobile et desktop.
-
Avant Critical :
- note mobile : 91/100
- note desktop : 97/100
-
Après Critical :
- note mobile : 99/100*
- note desktop : 99/100* (*le 1% restant est dû à… la présence du script Google Analytics)
Illustration avant critical :
Illustration après critical :
D’après Dareboost
Dareboost testé sur mobile (Nexus 5, en 3G et en France) attribue une note totale de 92% avant et après critical.
Avant Critical :
- chargement complet en 2.30s (visuellement complet en 1.37s)
- speed index de 607
Après Critical :
- chargement complet en 2.01s (visuellement complet en 0.80s)
- speed index de 436
Illustration : comparaison avant et après :
La tâche de mise en production
Voici la tâche complète de mise en production de l’ensemble des contenus de _src/
vers _dist/
que j’emploie :
// Tâche "prod" = toutes les tâches ensemble
gulp.task('prod', gulpsync.sync(['css', 'js', 'html', 'critical','img']));
En un clic, voici les actions menées automatiquement :
- styles LESS compilés en CSS
- préfixes CSS3 ajoutés au besoin
- concaténation et minification des fichiers CSS
- concaténation et minification des fichiers JavaScript
- optimisation des images PNG, JPG et SVG
- compilation des fichiers HTML pour permettre les inclusions de fichiers partiels et des variables
- “inline” des styles CSS “critiques” directement dans la page
Et pour finir, voici la tâche "watch" qui va surveiller en continu toutes les modifications opérées sur les fichiers LESS et HTML et qui va automatiquement lancer les tâches correspondantes :
// Tâche "watch" = je surveille LESS et HTML
gulp.task('watch', function () {
gulp.watch(source + '/assets/css/*.less', ['css']);
gulp.watch(source + '/{,conf/}/{,livres/}*.html', ['html']);
});
Si l'envie vous prend et si vous avez envie de tester tout ça chez vous, vous pouvez récupérer les fichiers package.json
et gulpfile.js
sur mon espace Gist.
Que conclure de tout ça ?
Disposer d'un environnement de travail automatisé (au moins en partie) est devenu une évidence de nos jours où nous ne pouvons plus nous contenter d'écrire du HTML et du CSS. L'industrialisation de notre métier exige d'aller vite, de tester sur de nombreux devices, d'éviter les régressions, de maintenir son code et de le rendre le plus performant possible.
Des outils tels que Grunt, Gulp ou Brunch offrent un "workflow" automatique pour la plupart des tâches courantes.
Pour ce qui est du reste, par exemple inclure des fichiers en HTML ou rendre inline ses CSS "critiques"... il y a aussi une application pour ça ! :)
Commentaires
Ohhhh un gros merci pour l'article.
Mon workflow ressemble tout de même beaucoup mais j'avoue avoir eu le même enjeu face aux includes. J'avais fait des recherches mais n'avais rien trouvé de concluant. Là je vais clairement faire un test avec gulp-html-extend. (Certainement aussi pour unCSS).
Si cela te dit, je suis en train de finaliser un worklow complet avec Slush-generator. Dans celui j'ai créé, en ligne de commande, tu entre un nom de dossier, il le crée local, "init" un git si nécessaire, le crée sur bitbucket (j'ai aussi une version sur gitlab), va chercher sur git un template backend, un template front-end, met le tout ensemble, push le premier commit et ensuite start ton npm install, bower et finalement gulp.
Je suis à le pousser encore plus loin pour modifier son fichier host, et vhost pour pouvoir directement utiliser par la suite mamp ou wamp.
Si cela vous intéresse je vous intéresse j'incluerai un lien ici vers le git de mon générateur.
Pas mal, vraiment intéressant. Par contre ça atteint vite des limites lorsqu'il faut intégrer les données du back end non ? Une solution avec Twig ou Smarty ?
Chez nous on bosse sur Zend avec Smarty et nos "workspaces" sont sur un serveur local sur lequel on fait watcher inotify pour compiler automatiquement les fichier SCSS en CSS (avec autoprefixr et de la minification etc...). On utilise Gulp en local pour tout ce qui va être création d'icon font (sans passer par icomoon) et optimisation images.
L'article me donne des idées pour améliorer le workflow de mon équipe, je vais donc m'y pencher un peu dessus ce week end, tu m'as donné envie ;)
Super article, merci beaucoup !!
J’ai deux questions, dont une probablement idiote :
— il me semblerait logique que l’ordre d’exécution des tâches soit crucial mais ça n’est pas mentionné : est-ce bien le cas ?
— sur un plan purement pratique dans l’utilisation de unCSS notamment : est-ce utilisable en travaillant sur un thème WordPress (par ex.) ? Dans le workflow décrit, les inclusions HTML sont gérées donc j’aurais tendance à croire que oui…
Moi qui suis prudent par nature et attends toujours que le train passe avant de me lancer (j’ai attendu longtemps avant de jouer avec un pré-processeur), le workflow décrit dans cet article me donne vraiment envie d’essayer un gestionnaire de tâches :)
Merci pour l'article,
Pour aller plus loin dans cette démarche on peut aussi minifier le HTML
https://www.npmjs.com/package/gulp-minify-html
Merci pour cet article ! J'ai une question concernant Critical. Tu spécifie une hauteur et une largeur spécifique dans ta tâche gulp mais dans une logique responsive comment faire pour prendre en compte les différentes résolutions de la multitude de devices qui visitent notre site ?
@incube : Je serai très intéressé de voir le git de ton générateur. Ca à l'air très complet :)
@Luchenzo : je n'ai jamais testé, mais il semble que ce soit prévu :
https://github.com/addyosmani/critical#generate-critical-path-css-with-multiple-resolutions
@Ten : Je ne suis pas spécialiste WordPress, je vais laisser la main aux connaisseurs pour répondre à cette question.
Pour ce qui est de l'ordre des tâches, il est important que Critical s'exécute à la fin du process HTML/CSS. Le reste est assez indépendant.
@seufer : nous avons encore quelques réticences avec la minification HTML. Même si on peut la configurer, il se peut que l'affichage final ne soit pas celui initial (par exemple les whitespace pour les inline-block). Et le gain n'est pas si énorme que ça. Mais pourquoi pas.
@incube : Oui ça m'intéresse aussi :)
Merci pour ce partage.
Cependant je ne comprends pas pourquoi ces tâches (LESS, autoprefixer, minification, concaténation, include HTML...) ne sont pas exécutées en local, pour ensuite uploadé directement les fichiers générés sur le serveur ?
@Raphael il y a une légère erreur dans la tâche prod de votre workflow.
Les tâches gulps sont lancés en asynchrone, et sachant que la tâche critical est dépendante de la tâche html, sa peut poser problème, dans le cas où la tâche critical commence à s'exécuter avant que la tâche html ne soit fini.
Donc dans votre cas, il faut utiliser la librairie gulp.sync qui permet (simplement) d'avoir une liste de dépendance synchrone.
Ou sinon inclure la modification critical directement dans le flux de la tâche html (si possible)
@maarekj : il me semble - je me trompe peut-être, mais le fait de précéder chaque tâche d'un "return" la rend synchrone. J'avais justement des problèmes "avant".
Je ne me rappel pas que le fait de faire un return rendez la tâche synchrone pour la dépendance. (par contre pour gulp.sync il faut bien laisser ce return).
A vérifier si sa rend vraiment ma tâche synchrone ou si votre critical ne fonctionne pas sur les fichier html déjà présent dans prod avant la fin de la tâche html (présente par le biais d'une ancienne génération complète par exemple).
@Ben31 : dans le cas où tu travailles dans une équipe de plusieurs devs, cela te permet de versionner les fichiers source, ce qui est très importants.
Les tâches de minification, concaténation (etc) sont ensuite exécutées au moment du build.
@Raphaël : dans la rubrique "gestion des tâches courantes" j'aurais ajouté jshint, juste avant uglify. De mémoire tu l'utilisais sous ST2, mais bon, quitte à créer un workflow pour toute l'équipe...
@Olivier C : A vrai dire, il y a certaines opérations que nous préférons effectuer chacun sur notre poste. Il s'agit des CSSlint, JShint, CSScomb et autre Beautify.
Nous préférons encore avoir la main sur ces tâches plutôt que de les automatiser et c'est pourquoi nous les incluons au niveau de notre IDE via des plugins.
@Raphael il y a une légère erreur dans la tâche prod de votre workflow.
Les tâches gulps sont lancés en asynchrone, et sachant que la tâche critical est dépendante de la tâche html, sa peut poser problème, dans le cas où la tâche critical commence à s'exécuter avant que la tâche html ne soit fini.
Donc dans votre cas, il faut utiliser la librairie gulp.sync qui permet (simplement) d'avoir une liste de dépendance synchrone.
Ou sinon inclure la modification critical directement dans le flux de la tâche html (si possible)
@maarekj: votre remarque me fait penser à un truc du même genre lu sur le bloc "Putain de code".
@maarekj : Oui tu as raison. Après tests, il ne suffit pas de précéder les tâches d'un "return".
Je viens de rajouter gulp-sync dans la boucle et ça fonctionne très bien, merci.
Vous laissez la concaténation à la charge de less ? Ça fait beaucoup de choses à écrire pour rien finalement, un concatèneur de css dédié simplifierait encore le workflow, on garde les @import de less pour la gestion des variables et on concatène tous les fichiers après avoir compilé en css, juste avant de passer à la moulinette du uncss (du feu de Dieu ce truc, je connaissais pas, merci de m'avoir fait découvrir).
@DracoRPG : Je ne vois pas trop en quoi cela fait beaucoup de choses à écrire pour rien. La concaténation est automatique avec LESS : chaque fichier est @importé dans un fichier unique :
https://github.com/raphaelgoetter/KNACSS/tree/master/less
Pour le "trop" à écrire, je pensais justement à toute les @import, en concaténant avec less, on est obligé de garder un fichier à jour incluant tous les fichiers à inclure, long et rébarbatif si on à tendance comme moi à beaucoup (trop ?) découper son code et à sortir des dizaines de fichiers de style.
Mais c'est vrai qu'à la réflexion je ne sais pas vraiment si c'est mieux.
@Raphael : Pour ma question concernant l’utilisation de unCSS dans un projet WordPress, c’est effectivement possible mais en fournissant des URLs (locales ou en ligne). On ne peut pas tester le répertoire du thème directement car unCSS « se contente » d’ouvrir des fichiers HTML dans PhantomJS : il nous faut donc une version statique.
C’est un peu moins pratique que dans le workflow décrit par l’article mais c’est jouable si on connait par avance ses templates :-)
Bonjour,
A propos de gulpsync, de mon côté je n'ai pas l'impression que cela fonctionne correctement.
J'ai une tâche qui ressemble à ça :
gulp.task('pages_fr', gulpsync.sync([
'json_fr', 'jade_fr'
]));
En gros, json_fr est une tâche de concaténation de mes fichiers *.json et jade_fr compile mes fichiers *.jade en allant chercher les données dans le json concaténé. Si je fais une modification dans mes *.json et bien la modification n'est pas prise en compte, il faut que je relance une deuxième fois la tâche pour que ce soit bon... Bizarre, non ?
En complément pour wordpress : http://code.tutsplus.com/tutorials/using-gulp...
Merci pour le partage. Il y a aussi gulp plumber qui évite de relancer une tâche manuellement si elle pète.
https://www.npmjs.com/package/gulp-plumber/
Il y a aussi gulp-notify qui peut être utile : https://github.com/mikaelbr/gulp-notify
Je suis retourner à prepros pour plus de simplicité mais les tâches uncss et critical sont manquante et apportent une vraie plus value.
Tu fais comment pour bosser avec les plugins Gulp ? Ils sont dans le dossier de ton projet ou tu les appelles de manière globale ?
@David-Dante : merci pour les idées de plugins. Je les avais déjà vu passer mais ils ne m'ont pas tant excité que ça ;)
Sinon, les plugins sont dans le dossier de mon projet. Tu faisais différemment toi ?
Non, mes plugins étaient aussi dans le dossier du projet. Ça m'agaçait un peu. On utilise les mêmes pour chaque projet donc j'aurais aimé les utiliser de manière globale au lieu de prendre de la place sur mon disque dur pour rien.
J'ai essayé une recherche et il semblerait qu'on puisse utiliser les plugins de manière globale. Il faut se placer dans son dossier de projet en ligne de commande et faire un npm link gulp + les noms des autres plugins.
J'ai fait un test rapide sur un projet où j'ai utilisé gulp et ça à l'air de fonctionner.
C'est une bonne nouvelle pour moi.
Ça mérite une reconsidération mon workflow.
Bonjour et merci pour cet article ... Je reviens sur la question de l'ordre: lorsque tu écris ou se trouvent les fichiers à surveiller / concatener / minifier : ..css/*.css, ../js/*.js, les fichiers sont pris dans l'ordre dans lequel ils se trouvent dans l'arborescence du serveur, et donc, pas forcément dans l'ordre souhaité.
Il me semble que cela devrait poser problème parfois.
@David-Dante : Ah voilà une info intéressante en effet. Je vais tester ça aussi.
Par contre, il est nécessaire de faire un npm link de chacun de ses plugins (sachant que j'en ai un paquet dans mon package) ?
Oui mais ça change rien non ? Au lieu de faire un npm install + les noms de tout tes plugins à installer, tu fais un npm link + les noms de tout tes plugins.
J'ai oublié de parler de pleeease dans les plugins intéressants aussi. Un petit couteau suisse à lui tout seul. ^^
@David-Dante : En fait je ne fais jamais"npm install + les noms de tout tes plugins à installer" mais uniquement "npm Install" puisque tous mes plugins sont définis dans le package.json
Ça change donc pas mal de choses di je dois tous les linker un par un.
Je ne connaissais pas cette astuce.
En théorie, je pensais qu'en remplaçant le npm install par npm link ça fonctionnerai mais c'est un fail. Si tu fait un npm link, il télécharge quand même les dépendances. Dommage.
Bon je préfère quand même faire un copié collé d'une -longue- ligne de commande que je stocke sur mon pc qu'une installation de milliers de fichiers qui sont déjà présent sur mon ordinateur.
@David-Dante : Et penses-tu qu'il suffirait de copier-coller simplement les dossiers virtuels (node) d'un projet à un autre ?
@Raphael : J'ai testé et la réponse est non. Windows copie les dossiers à l'intérieur des node_modules en tant que dossiers et non comme liens vers l'installation globales des dépendances que tu utilises.
Comme j'ai un projet perso à intégrer, j'en profite pour réévaluer Gulp face à prepos.
Les includes HTML empêchent d'ajouter la classe "current" et ça m’embête. :/
J'espère que uncss et critical vont fonctionner avec mes fichiers php.
Sinon, je viens de trouver ça : https://www.npmjs.com/package/gulp-php2html/
À tester.
Salut,
Après réflexion, je reste avec Prepros tout en intégrant Gulp pour les finitions.
J'avais décidé de réétudier Gulp pour uncss et critical parce que la webperf, c'est mon dada.
Pour le reste des tâches, Prepros les exécute finger in the node.
Du coup, je suis parti pour intégrer rester avec Prepros pendant la phase de dev et avant d'envoyer en prod, je passerai un coup de polish avec gulp et les plugins suivant :
- Gulp-pleeease : préfixe, rassemble les MQ similaires et minifie le code.
- Gulp uncss : pour virer toutes les classes "helpers" inutilisées de mon framework scss qui va être proposé publiquement avant la prochaine comète de Halley. Pour info, cette tache fonctionne sur des fichiers php à condition de travailler avec des virtualhosts.
- Gulp rename.
Malheureusement, je n'ai pas réussi à faire fonctionner critical sur des fichiers PHP. :/
C'est dommage parce que j'ai juste besoin de php pour tester et ajouter une classe "current-page". :(
Le gain est quand même suffisamment conséquent pour que je m'y attarde.
@loicbcn : Tout à fait, c'est pourquoi il faut déclarer les fichiers problématiques un par un en les séparant par des virgules. Ce qui devient moins souple d'utilisation bien sûr étant donné qu'il faudra reconfigurer son Gulp à chaque fois que l'on fera un ajout de fichier.
Bon, j'ai passé une journée avant hier à passer mon workflow de Grunt à Gulp. Pas facile de reparamétrer exactement toutes les fonctionnalités à l'identique, mais ça c'est normal.
À l'utilisation j'ai trouvé Gulp beaucoup plus instable que Grunt. Sur le traitement de gros fichiers on peut avoir de mauvaises surprises, ce qui ne m'était jamais arrivé avec Grunt. Je vais tester les gulp.sync (j'utilise pourtant un return dans mes fonctions), plumber et d'autres patchs pour solidifier tout ça...
Ah oui d'accord : gulp.sync c'est pour les options passées en tableaux. Ça me résout déjà pas mal de problèmes, notamment pour le livereload.
Salut,
Je viens d'avoir un soucis avec Uncss. Il supprime les règles :not().
Dans le gulpfile.js, il suffit d'ajouter : ignore : [/not/] après la déclaration du HTML. Dans l'exemple de Raphaël, ça donne :
.pipe(uncss({
html: [source + '/{,_includes/}/{,conf/}/{,livres/}*.html'],
ignore : [/not/]
}))
@David-Dante : Tu as une source ? Cela me semble assez peu probable vu qu'il s'agit d'un navigateur qui"lit" vraiment la page.
Par contre ce qui est juste est qu'il parcourt cette page à un instant T et qu'il ne peut pas deviner si JavaScript actionne des classes CSS. Ces classes dynamiques seront donc invisibles pour lui et il va les supprimer.
C'est ce qui m'arrive sur ma navigation: la classe .is-open est activée en JavaScript. Du coup unCSS supprime cette classe importante de mes styles.
Il faut effectivement ajouter un ignore. Je vais en dire un mot sur l'article, merci.
Merci pour l'article ! j'ai hate de passer à la pratique.
@Raphael : J'ai plus vraiment de source comme c'est un problème qui m'est arrivé et que je l'ai résolu. J'utilise ton menu responsive en JS et pour le styler uniquement quand il est fermé, j'utilise :not(.is-open). C'est en vérifiant mon site "prod" que j'ai constaté qu'uncss n'avait pas inclus cette règle.
Tout est rentré dans l'ordre avec l'ajout de l'exception.
Ça ne venait pas de l'ajout de classe JS dans mon cas.
@David-Dante : Dans mon menu Responsive en JS, la classe .is-open est ajoutée via JavaScript, d'où le problème. J'ai ajouté cette partie dans l'article.
Super article !
Et en comparant Gulp à Brunch, j'ai l'impression que Gulp possède beaucoup de plugins. Brunch à l'air plus simple à mettre en place et plus performant. Dommage qu'on ne puisse pas utiliser html-extend ou critical avec celui-ci...
Pour le moment, je privilégie donc Gulp dans la mesure où sa communauté est plus active, il a plus de plugins.
Par contre, j'ai un problème avec la tache des [scripts] proposée :
"ERROR: can't find config file: .jshintrc"
Vous avez une idée ?
Merci
@Raphael : Je pensais que ça venait de :not mais tu as raison, ça vient des classes ajoutées en JS.
Sinon, Critical est assez capricieux avec les sous-répertoires.
gulp.src('./dist/**/*.html') ne traite que les pages situés à la racine donc il faut rusé un peu et mettre :
return gulp.src([
'./dist/**/*.html',
'./dist/**/nom-de-votre-page.html'
])
Et la magie s'opère, même si ça demande un peu plus de travail.
@itisinspiring : arf en fait c'est à moi de créer le fichier .jshintrc pour configurer le plugin :-|
Sinon, depuis que j'utilise Gulp avec Autoprefixer, je laisse tomber Compass mais je n'arrive pas à comprendre comment gérer les sprites désormais, et les plugins proposés sont pas évidents à comprendre...
@NikoLP : Bonjour, pour évaluer des données backend et précisément tout ce qui gravite autour de PHP (Moteurs de templates, Cache etc) utilise plutôt Blackfire.io
@Raphael, j'ai adoré cet article. C'est avec lui que j'ai commencé à concevoir l'idée du worflow et m'en faire un moi-même. C'est vrai que ça facilite grandement les tâches, moi qui faisait tout à la main !
Par contre, j'aurais aimé avoir une information supplémentaire. Car, au risque de paraître idiote, je n'arrive pas à savoir de quel langage il s'agit, surtout pour le style "expression régulière" utilisé sur cette ligne :
html: [source + '/{,_includes/}/{,conf/}/{,livres/}*.html']
Je comprend bien l'explication fournie avec, mais j'aurais aimé avoir un lien ou un mémo sur les symboles à utiliser et leur signification, pour pouvoir construire ma propre regex.
En tout cas merci, ça a révolutionné ma façon de voir les choses, ma façon de travailler ! J'ai compris que je devais être ultra fainéante :D
Bon, je me répond à moi-même, si j'ai bien compris il s'agit de nodejs et python. Voilà, encore merci pour l'article - un changement radical rien que de ma logique de pensée !
Pour la petite histoire, comme on dit, je m'étais également penché sur ce problème d'intégration de fichiers html sans la lourdeur du php côté serveur. La solution que j'avais trouvé était d'écrire mon site en php, puis de "compiler" celui-ci en php à l'aide de wget.
Je mettais en ligne les fichiers .html et conservait les fichiers .php en local.
Des informations à
http://micr0lab.org/tech/php/#compiler_vers_h...
et
http://micr0lab.org/tech/scripts/#php_vers_ht...
Mais c'est de l'histoire ancienne : je suis déjà en train de passer à votre déroulement de travail, bien senti! Merci pour le partage.
Petit détail, bien penser à mettre /**/*.* dans les noms de dossiers pour optimiser les images, y compris s'il y a du sous-dossier dans le dossier images.
Merci pour ce chouette tuto en tout cas :)
Whaa ! ça déchire :
Je bien de configurer un système avec gulp-iconfont : je mets des SVG dans un dossier... et hop : transformation des tous les .svg en fonts .ttf, .woff autres + le CSS associé pour chaque glyph + un html de démo...
Voir le résultat ici : http://scriptura.github.io/Pages/GlyphIcons.h...
Le Gulpfile.js ici : https://github.com/Scriptura/Scriptura/blob/master/Gulpfile.js
Salut,
Un peu tardivement, je souhaite me mettre à Gulp, or le lien pour télécharger tes fichiers d'exemple est mort.
C'est possible de le réanimer s'il te plait ?
Merci pour cet excellent article en tout cas ;)
Hello la team,
merci pour l'article qui explique clairement html-extend, je sais pas je comprenais pas en lisant ailleurs.
BREF!
je voulais savoir s'il était possible d'inclure la task extend dans un runsequence avec sass/less et browsersync, j'ai bidouillé mais je n'y arrive pas, je n'ai pas d'erreur, mais ça n'affiche pas mes includes en live bien que mon dossier dist soit mise à jour a chaque refresh du run.
Je capte pas trop pourquoi :/
Petite help @Raphael ? ou qu'importe
Meeeeeerci beaucoup