Fedora-Fr - Communauté francophone Fedora - Linux

Planet de Fedora-Fr : la communauté francophone autour de la distribution Linux Fedora

A propos

Cette page est actualisée toutes les heures.

Cette page est une sélection de blogs autour de Fedora. Fedora-Fr.org décline toute responsabilité au sujet des propos tenus par les auteurs des blogs de ce planet. Leurs propos sont leur entière responsabilité.

Le contenu de ce planet appartient à leurs auteurs respectifs. Merci de consulter leur blogs pour obtenir les licences respectives.

Mot-clefs : Développement web

Data URIs VS CSS Sprites

Guillaume Kulakowski

J'ai profité de la sortie de la branche 2.7 de Dotclear et de l'arrivée de Twig comme moteur de template pour faire quelques modifications sur le blog :

  • Migration vers des templates utilisant la syntaxe Twig et utilisation au maximum de l'héritage (la killer feature de Twig !).
  • Utilisation encore plus massive de Less.
  • Mise à jour des librairies JS et CSS (merci Bower).
  • Suppression des sprites CSS pour utiliser des images en data URI au sein de mes CSS.

Et c'est sur ce dernier point que je souhaitais discourir...

Les sprites CSS c'est bien... mais c'est chi**t !!!

En effet, les sprites CSS c'est bien pour les performances web client side (notamment : Minimize HTTP Requests & Preload Components). Le problème, c'est que c'est chi**t à manipuler ! Il existe des générateurs de sprites, mais ce n'est pas la panacée. Bilan : j'y réfléchi à 2 fois avant de changer une image et dans certains cas il est même obligatoire de mixer plusieurs images sprites (sur des background-repeat bien complexes).

Data URI, L'alternative ?

La solution alternative c'est d'utiliser des data URIs, c'est à dire de mettre le code base64 de l'image directement dans la CSS (où une CSS séparée). Vous me direz que faire un sprite CSS ou faire un base64 c'est aussi pénible et je vous répondrais oui... Si on travaille en pure CSS ! Mais si on utilise Less (et c'est surement aussi possible en Sass) il y a une fonction qui fait ça automatiquement !

Y a-t-il que des avantages ?

Malheureusement non.

  • Un fichier CSS avec du base64 pèse 25% (10% si on utilise compression gzip) de plus qu'un sprite.
  • Les data URI's ne sont pas supportées par IE6/7 (ça je m'en fous un peu :-)).
  • Les performances sont quelques peu en dessous d'un sprite.

En conclusion

J'ai déjà pas mal optimisé mon site, le fait de passer par data-uri me permet de :

  • Réduire le poids général de ma CSS (j'embarquais déjà quelques data-uri que je viens de délocaliser dans une CSS à part).
  • Pouvoir rapidement faire évoluer mon image sprites (retirer les images inutiles par exemple) et gagner en time to market.

Bref : adopté !

Data URIs VS CSS Sprites

Guillaume Kulakowski

J'ai profité de la sortie de la branche 2.7 de Dotclear et de l'arrivée de Twig comme moteur de template pour faire quelques modifications sur le blog :

  • Migration vers des templates utilisant la syntaxe Twig et utilisation au maximum de l'héritage (la killer feature de Twig !).
  • Utilisation encore plus massive de Less.
  • Mise à jour des librairies JS et CSS (merci Bower).
  • Suppression des sprites CSS pour utiliser des images en data URI au sein de mes CSS.

Et c'est sur ce dernier point que je souhaitais discourir...

Les sprites CSS c'est bien... mais c'est chi**t !!!

En effet, les sprites CSS c'est bien pour les performances web client side (notamment : Minimize HTTP Requests & Preload Components). Le problème, c'est que c'est chi**t à manipuler ! Il existe des générateurs de sprites, mais ce n'est pas la panacée. Bilan : j'y réfléchi à 2 fois avant de changer une image et dans certains cas il est même obligatoire de mixer plusieurs images sprites (sur des background-repeat bien complexes).

Data URI, L'alternative ?

La solution alternative c'est d'utiliser des data URIs, c'est à dire de mettre le code base64 de l'image directement dans la CSS (où une CSS séparée). Vous me direz que faire un sprite CSS ou faire un base64 c'est aussi pénible et je vous répondrais oui... Si on travaille en pure CSS ! Mais si on utilise Less (et c'est surement aussi possible en Sass) il y a une fonction qui fait ça automatiquement !

Y a-t-il que des avantages ?

Malheureusement non.

  • Un fichier CSS avec du base64 pèse 25% (10% si on utilise compression gzip) de plus qu'un sprite.
  • Les data URI's ne sont pas supportées par IE6/7 (ça je m'en fous un peu :-)).
  • Les performances sont quelques peu en dessous d'un sprite.

En conclusion

J'ai déjà pas mal optimisé mon site, le fait de passer par data-uri me permet de :

  • Réduire le poids général de ma CSS (j'embarquais déjà quelques data-uri que je viens de délocaliser dans une CSS à part).
  • Pouvoir rapidement faire évoluer mon image sprites (retirer les images inutiles par exemple) et gagner en time to market.

Bref : adopté !

Passage d'Eclipse à Netbeans

Guillaume Kulakowski

Après des années et des années de bons et loyaux services, j'ai décidé d'arrêter d'utiliser Eclipse.

Les raisons sont multiples :

  • Eclipse est de plus en plus lourd alors que la mode est aux IDE de plus en plus légers (SublimeText, Atom.io, etc...).
  • Je ne fais plus de Java depuis longtemps. J'ai besoin d'un IDE qui permette de faire du web (CSS, HTML, JS, Less, etc...), PHP, Node, Ruby, shell. Or Eclipse devient de plus en plus inadapté pour cela.
  • J'ai besoin d'un IDE avec une thème dark. Alors sous Linux pas de problème, mais au travail, sous Windows (sniff), je n'ai jamais pu avoir de thème dark sans un détourage désagréable des icônes.

C'est pour toutes ces raisons que j'ai souhaité changer de crèmerie. Mais je n'étais pas prêt pour passer à un truc trop light, je suis donc allé chercher la solution d'en face : Netbeans. Alors ne nous emballons pas, avec Netbeans tout n'est pas rose :

  • Netbeans permet d'avoir une syntaxe par langage, mais ça veut direz coder tous les frameworks PHP de la même façon... Du Drupal et du Symfony2, ça ne se code pas pareil (hélas).
  • Le plugin GIT est simple et efficace mais un peu trop simple quand même.

Mais il y a des trucs qui sont en train de me devenir indispensables :

  • Terminal intégré nativement.
  • Plugin Vagrant.
  • Stack d'outils PHP qui fonctionnent sans PEAR.
  • Support de Composer, NPM, Bower et du Less out-of-the-box.

Après avoir changé le moteur, j'ai également changé la carrosserie :

Et voici le résultat :

Netbeans.png

Passage d'Eclipse à Netbeans

Guillaume Kulakowski

Après des années et des années de bons et loyaux services, j'ai décidé d'arrêter d'utiliser Eclipse.

Les raisons sont multiples :

  • Eclipse est de plus en plus lourd alors que la mode est aux IDE de plus en plus légers (SublimeText, Atom.io, etc...).
  • Je ne fais plus de Java depuis longtemps. J'ai besoin d'un IDE qui permette de faire du web (CSS, HTML, JS, Less, etc...), PHP, Node, Ruby, shell. Or Eclipse devient de plus en plus inadapté pour cela.
  • J'ai besoin d'un IDE avec une thème dark. Alors sous Linux pas de problème, mais au travail, sous Windows (sniff), je n'ai jamais pu avoir de thème dark sans un détourage désagréable des icônes.

C'est pour toutes ces raisons que j'ai souhaité changer de crèmerie. Mais je n'étais pas prêt pour passer à un truc trop light, je suis donc allé chercher la solution d'en face : Netbeans. Alors ne nous emballons pas, avec Netbeans tout n'est pas rose :

  • Netbeans permet d'avoir une syntaxe par langage, mais ça veut direz coder tous les frameworks PHP de la même façon... Du Drupal et du Symfony2, ça ne se code pas pareil (hélas).
  • Le plugin GIT est simple et efficace mais un peu trop simple quand même.

Mais il y a des trucs qui sont en train de me devenir indispensables :

  • Terminal intégré nativement.
  • Plugin Vagrant.
  • Stack d'outils PHP qui fonctionnent sans PEAR.
  • Support de Composer, NPM, Bower et du Less out-of-the-box.

Après avoir changé le moteur, j'ai également changé la carrosserie :

Et voici le résultat :

Netbeans.png

Grunt, Bower, LESS & Bootstrap

Guillaume Kulakowski
Dans mon dernier billet, j'avais évoqué mon engouement pour Bower, une solution de gestion de dépendances web. J'avais alors regretté le fait de ne pas pouvoir exécuter des tâches post-installation afin de retravailler la version distribuée de Bootstrap pour lalléger (comme on peut le faire ici). Comme j'en avais émis l'idée dans ce même billet, j'ai entrepris de ne plus utiliser Bower directement mais de lutiliser au travers de Grunt.

grunt-bower.png

Si vous ne connaissez pas encore Grunt, il s'agit d'un ordonnanceur au même titre que Maven, ant, ou encore Phing, mais basé sur nodejs et utilisant une syntaxe JavaScript.

Installation de Bower & Grunt sous Fedora 20

Après avoir installé nodejs et npm via yum, il faudra installer Bower et Grunt avec npm. En effet, Bower est absent des dépôts Fedora et Grunt est bien disponible mais sans grunt-cli, ce qui en enlève tout lintérêt...

sudo yum install npm -y
sudo npm install bower grunt grunt-cli -g

Notez au passage le fait que l'on fasse l'installation avec l'option -g pour avoir Grunt et Bower installés au niveau du système (/usr/lib/node_modules). Les autres installations se feront toujours à l'aide de npm mais sans cette option. Ceci permet de tout avoir à la racine du projet web, dans un répertoire node_modules (qu'il faudra exclure de la gestion de sources).

Voila, maintenant on rajoute un fichier packages.json et on installe les dépendances avec un npm install :

{
  "name": "Boldy",
  "version": "1.1.2",
  "description": "The Boldy theme for Dotclear",
  "repository": {
    "type": "git",
  },
  "author": "Guillaume Kulakowski",
  "homepage": "http://www.llaumgui.com",
  "devDependencies": {
    "bower": "latest",
    "grunt": "~0.4.2",
    "grunt-contrib-uglify": "latest",
    "grunt-contrib-concat": "latest",
    "grunt-contrib-less": "latest",
    "grunt-bower-task": "latest",
    "grunt-contrib-watch": "latest"
    "grunt-contrib-cssmin": "latest"
  }
}

J'ai maintenant un environnement de travail avec Bower et Grunt ainsi que les plugins nécessaires à mon projet.

Le fichier Gruntfile.js

La configuration des tâches Grunt passe par le fichier Gruntfile.js, j'ai mis le mien et vais en détailler les tâches :

module.exports = function(grunt) {
  'use strict';
 
  // Force use of Unix newlines
  grunt.util.linefeed = '\n';
 
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    bowerrc: grunt.file.readJSON('.bowerrc'),
 
    // Path configuration from Gruntfile.js
    dirs: {
      'vendor': '<%= bowerrc.directory %>',
      'bootstrap': {
        'js': '<%= dirs.vendor %>/bootstrap/js',
        'less': '<%= dirs.vendor %>/bootstrap/less'
      },
      'css': 'css',
      'less': 'less',
      'js': 'js'
    },
 
    src: {
      output: {
        'bootstrap': {
          'js': '<%= dirs.vendor %>/bootstrap/my/js/bootstrap.js',
          'css': '<%= dirs.vendor %>/bootstrap/my/css/bootstrap.css'
        },
        'boldy': {
          css: {
            'screen': '<%= dirs.css %>/screen.css',
            'indefero': '<%= dirs.css %>/indefero.css'
          },
          js: '<%= dirs.js %>/global.js'
        }
      },
 
      input: {
        bootstrap: {
          'js': [
            '<%= dirs.bootstrap.js %>/dropdown.js',
            '<%= dirs.bootstrap.js %>/tooltip.js',
            '<%= dirs.bootstrap.js %>/collapse.js',
            '<%= dirs.bootstrap.js %>/transition.js',
            '<%= dirs.bootstrap.js %>/carousel.js'
          ],
          'less': [
            '<%= dirs.less %>/bootstrap.less'
          ]
        },
        indefero: '<%= dirs.css %>/indefero.src.css',
        less: '<%= dirs.less %>/boldy_boot.less',
        js: [
          '<%= dirs.vendor %>/jquery-cookie/jquery.cookie.js',
          '<%= src.output.bootstrap.js %>',
          '<%= dirs.vendor %>/scroll-to-top/jquery.scrollToTop.min.js',
          '<%= dirs.js %>/js/post.js',
          '<%= dirs.vendor %>/async-gravatars/async-gravatars.js',
          '<%= dirs.vendor %>/jquery-colorbox/jquery.colorbox-min.js',
          '<%= dirs.vendor %>/nwxforms/src/nwxforms.js',
          '<%= dirs.js %>/boldy.js'
        ]
      },
    },
 
    // Banner
    banner: '/*!\n' +
              ' * Boldy for Dotclear v<%= pkg.version %>\n' +
              ' * Original theme by Site5 (http://www.s5themes.com)\n' +
              ' * Under a GPLv2 http://www.gnu.org/licenses/gpl-2.0.txt\n' +
              ' * Ported on Dotclear by <%= pkg.author %> (<%= pkg.homepage %>)\n' +
              ' * Copyright 2012-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
              ' */',
 
 
 
    /********************************** Task **********************************/
    // Bower
    bower: {
      install: {
        options: {
          targetDir: '<%= dirs.vendor %>',
          cleanTargetDir: true,
          layout: 'byComponent',
          install: true,
          copy: false,
          verbose: true
        }
      }
    },
 
 
    // Concatenation
    concat: {
      bootstrap: {
        src: '<%= src.input.bootstrap.js %>',
        dest: '<%= src.output.bootstrap.js %>'
      },
    },
 
 
    // LESS
    less: {
      boldy: {
        options: {
          compress: true,
          cleancss: true,
          report: 'gzip',
          strictImports: true,
        },
        files: { '<%= src.output.boldy.css.screen %>': '<%= src.input.less %>'},
      },
      boldy_debug: {
          options: {
            compress: false,
            cleancss: false,
            report: 'none',
            strictImports: true,
          },
          files: { '<%= src.output.boldy.css.screen %>': '<%= src.input.less %>'},
      },
      bootstrap: {
        files: { '<%= src.output.bootstrap.css %>': '<%= src.input.bootstrap.less %>'}
      }
    },
 
 
    // Watcher
    watch: {
      boldy: {
        files: ['less/*.less'],
        tasks: ['less:boldy_debug'],
        options: {
          spawn: false,
        },
      },
    },
 
 
    // CSSmin
    cssmin: {
      boldy: {
        options: {
          report: 'gzip',
          banner: '<%= banner %>'
        },
        files: {
          '<%= src.output.boldy.css.indefero %>': '<%= src.input.indefero %>'
        }
      }
    },
 
 
    // Uglify
    uglify: {
      boldy: {
        options: {
          report: 'gzip',
          banner: '<%= banner %>'
        },
        files: {
          '<%= src.output.boldy.js %>': '<%= src.input.js %>',
        }
      }
    }
 
  });
 
 
  // Load plugins
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-bower-task');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
 
 
  // Callable tasks
  grunt.registerTask('default', ['boldy', 'cssmin', 'concat:bootstrap', 'uglify']);
  grunt.registerTask('w', ['watch:boldy']);
 
  grunt.registerTask('bootstrap', ['concat:bootstrap', 'less:bootstrap']);
  grunt.registerTask('boldy', ['less:boldy']);
 
  grunt.registerTask('full', ['bower', 'bootstrap', 'default']);
  grunt.registerTask('all', ['full']); // Alias
};

Tâche bower

Via le plugin grunt-bower-task.

Cette tâche est là pour exécuter Bower au travers de Grunt, notez que le plugin n'interprète pas le .bowerrc, je l'ai donc chargé moi même (bowerrc: grunt.file.readJSON('.bowerrc')) afin de passer les mêmes options à la tâche Grunt qu'à Bower.

Tâche Bootstrap

Via les plugins grunt-contrib-less & grunt-contrib-concat.

Le but de cette tâche est de ne pas utiliser la version distribuée de Bootstrap mais de reconstruire ma propre version. Pour celà,

  • je reconstruis le JavaScript à partir des sources et du plugin concat,
  • je recompile les CSS à partir d'une version allégée du bootstrap.less :
/* -- BEGIN LICENSE BLOCK ---------------------------------------
# This file is part of Boldy, a theme for Dotclear
#
# Theme by Site5 (http://www.s5themes.com)
# under a GPLv2 http://www.gnu.org/licenses/gpl-2.0.txt
# Ported on Dotclear by Guillaume Kulakowski (http://www.llaumgui.com)
#
# -- END LICENSE BLOCK ----------------------------------------- */
 
// Core variables and mixins
@import "../vendor/bootstrap/less/variables.less";
@import "../vendor/bootstrap/less/mixins.less";
 
// My override
@import "bootstrap_variables.less";
//@import "bootstrap_mixins.less";
 
// Reset
@import "../vendor/bootstrap/less/normalize.less";
@import "../vendor/bootstrap/less/print.less";
 
// Core CSS
@import "../vendor/bootstrap/less/scaffolding.less";
@import "../vendor/bootstrap/less/type.less";
@import "../vendor/bootstrap/less/code.less";
@import "../vendor/bootstrap/less/grid.less";
//@import "../vendor/bootstrap/less/tables.less";
@import "../vendor/bootstrap/less/forms.less";
@import "../vendor/bootstrap/less/buttons.less";
 
// Components
@import "../vendor/bootstrap/less/component-animations.less";
//@import "../vendor/bootstrap/less/glyphicons.less";
@import "../vendor/bootstrap/less/dropdowns.less";
//@import "../vendor/bootstrap/less/button-groups.less";
//@import "../vendor/bootstrap/less/input-groups.less";
@import "../vendor/bootstrap/less/navs.less";
@import "../vendor/bootstrap/less/navbar.less";
//@import "../vendor/bootstrap/less/breadcrumbs.less";
@import "../vendor/bootstrap/less/pagination.less";
@import "../vendor/bootstrap/less/pager.less";
//@import "../vendor/bootstrap/less/labels.less";
//@import "../vendor/bootstrap/less/badges.less";
//@import "../vendor/bootstrap/less/jumbotron.less";
@import "../vendor/bootstrap/less/thumbnails.less";
@import "../vendor/bootstrap/less/alerts.less";
//@import "../vendor/bootstrap/less/progress-bars.less";
//@import "../vendor/bootstrap/less/media.less";
@import "../vendor/bootstrap/less/list-group.less";
@import "../vendor/bootstrap/less/panels.less";
@import "../vendor/bootstrap/less/wells.less";
//@import "../vendor/bootstrap/less/close.less";
 
// Components w/ JavaScript
//@import "../vendor/bootstrap/less/modals.less";
@import "../vendor/bootstrap/less/tooltip.less";
//@import "../vendor/bootstrap/less/popovers.less";
@import "../vendor/bootstrap/less/carousel.less";
 
// Utility classes
@import "../vendor/bootstrap/less/utilities.less";
@import "../vendor/bootstrap/less/responsive-utilities.less";

Remarquez que j'utilise mes propres variables après celles de Bootstrap afin de les écraser et de modifier Bootstrap directement à la source.

Tâche Boldy

Via les plugins grunt-contrib-uglify, grunt-contrib-less & grunt-contrib-cssmin.

Comme en recompilant Bootstrap à partir des sources LESS j'ai adhéré au concept de LESS, j'ai réécrit le thème de mon blog en LESS.

Cette tâche boldy sert donc :

  • à générer le CSS minifié à partir des sources LESS (grunt-contrib-less),
  • à minifier la CSS pour mon thème indefero qui reste en CSS (grunt-contrib-cssmin),
  • et à minifier les Javascripts (grunt-contrib-uglify).

Tâche watch

Via le plugin grunt-contrib-watch.

Pour compiler du LESS en CSS, il y a 2 méthodes.

  • soit passer par le less.js qui va parser en JS les fichiers LESS à chaque chargement de page (2 à 3 secondes pour mon blog),
  • soit passer par une tâche watch dans Grunt, qui va écouter les modifications sur les fichiers LESS et recompiler un CSS.

C'est cette dernière solution que j'ai retenu et donc c'est à cela que sert la tâche watch.

En conclusion

Pour conclure, je dirais que la mise en place de ces outils (surtout pour la première fois) est certes chronophage, mais une fois que ça tourne, pour mettre à jour les libs (Bootstrap, jQuery, etc.), une seule ligne de commande suffit (grunt full). De plus, une fois Grunt et Bower en place (et maîtrisés), passer de CSS à LESS a été super simple.

Pour finir, je regrette presque que nodejs n'ait pas été inclus dans Fedora plus tôt car il propose de formidables outils indispensables aux développeurs (front) web.

Et pour voir ce que ça donne, une petite vidéo:

Grunt, Bower, LESS & Bootstrap

Guillaume Kulakowski
Dans mon dernier billet, j'avais évoqué mon engouement pour Bower, une solution de gestion de dépendances web. J'avais alors regretté le fait de ne pas pouvoir exécuter des tâches post-installation afin de retravailler la version distribuée de Bootstrap pour lalléger (comme on peut le faire ici). Comme j'en avais émis l'idée dans ce même billet, j'ai entrepris de ne plus utiliser Bower directement mais de lutiliser au travers de Grunt.

grunt-bower.png

Si vous ne connaissez pas encore Grunt, il s'agit d'un ordonnanceur au même titre que Maven, ant, ou encore Phing, mais basé sur nodejs et utilisant une syntaxe JavaScript.

Installation de Bower & Grunt sous Fedora 20

Après avoir installé nodejs et npm via yum, il faudra installer Bower et Grunt avec npm. En effet, Bower est absent des dépôts Fedora et Grunt est bien disponible mais sans grunt-cli, ce qui en enlève tout lintérêt...

sudo yum install npm -y
sudo npm install bower grunt grunt-cli -g

Notez au passage le fait que l'on fasse l'installation avec l'option -g pour avoir Grunt et Bower installés au niveau du système (/usr/lib/node_modules). Les autres installations se feront toujours à l'aide de npm mais sans cette option. Ceci permet de tout avoir à la racine du projet web, dans un répertoire node_modules (qu'il faudra exclure de la gestion de sources).

Voila, maintenant on rajoute un fichier packages.json et on installe les dépendances avec un npm install :

{
  "name": "Boldy",
  "version": "1.1.2",
  "description": "The Boldy theme for Dotclear",
  "repository": {
    "type": "git",
  },
  "author": "Guillaume Kulakowski",
  "homepage": "http://www.llaumgui.com",
  "devDependencies": {
    "bower": "latest",
    "grunt": "~0.4.2",
    "grunt-contrib-uglify": "latest",
    "grunt-contrib-concat": "latest",
    "grunt-contrib-less": "latest",
    "grunt-bower-task": "latest",
    "grunt-contrib-watch": "latest"
    "grunt-contrib-cssmin": "latest"
  }
}

J'ai maintenant un environnement de travail avec Bower et Grunt ainsi que les plugins nécessaires à mon projet.

Le fichier Gruntfile.js

La configuration des tâches Grunt passe par le fichier Gruntfile.js, j'ai mis le mien et vais en détailler les tâches :

module.exports = function(grunt) {
  'use strict';
 
  // Force use of Unix newlines
  grunt.util.linefeed = '\n';
 
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    bowerrc: grunt.file.readJSON('.bowerrc'),
 
    // Path configuration from Gruntfile.js
    dirs: {
      'vendor': '<%= bowerrc.directory %>',
      'bootstrap': {
        'js': '<%= dirs.vendor %>/bootstrap/js',
        'less': '<%= dirs.vendor %>/bootstrap/less'
      },
      'css': 'css',
      'less': 'less',
      'js': 'js'
    },
 
    src: {
      output: {
        'bootstrap': {
          'js': '<%= dirs.vendor %>/bootstrap/my/js/bootstrap.js',
          'css': '<%= dirs.vendor %>/bootstrap/my/css/bootstrap.css'
        },
        'boldy': {
          css: {
            'screen': '<%= dirs.css %>/screen.css',
            'indefero': '<%= dirs.css %>/indefero.css'
          },
          js: '<%= dirs.js %>/global.js'
        }
      },
 
      input: {
        bootstrap: {
          'js': [
            '<%= dirs.bootstrap.js %>/dropdown.js',
            '<%= dirs.bootstrap.js %>/tooltip.js',
            '<%= dirs.bootstrap.js %>/collapse.js',
            '<%= dirs.bootstrap.js %>/transition.js',
            '<%= dirs.bootstrap.js %>/carousel.js'
          ],
          'less': [
            '<%= dirs.less %>/bootstrap.less'
          ]
        },
        indefero: '<%= dirs.css %>/indefero.src.css',
        less: '<%= dirs.less %>/boldy_boot.less',
        js: [
          '<%= dirs.vendor %>/jquery-cookie/jquery.cookie.js',
          '<%= src.output.bootstrap.js %>',
          '<%= dirs.vendor %>/scroll-to-top/jquery.scrollToTop.min.js',
          '<%= dirs.js %>/js/post.js',
          '<%= dirs.vendor %>/async-gravatars/async-gravatars.js',
          '<%= dirs.vendor %>/jquery-colorbox/jquery.colorbox-min.js',
          '<%= dirs.vendor %>/nwxforms/src/nwxforms.js',
          '<%= dirs.js %>/boldy.js'
        ]
      },
    },
 
    // Banner
    banner: '/*!\n' +
              ' * Boldy for Dotclear v<%= pkg.version %>\n' +
              ' * Original theme by Site5 (http://www.s5themes.com)\n' +
              ' * Under a GPLv2 http://www.gnu.org/licenses/gpl-2.0.txt\n' +
              ' * Ported on Dotclear by <%= pkg.author %> (<%= pkg.homepage %>)\n' +
              ' * Copyright 2012-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
              ' */',
 
 
 
    /********************************** Task **********************************/
    // Bower
    bower: {
      install: {
        options: {
          targetDir: '<%= dirs.vendor %>',
          cleanTargetDir: true,
          layout: 'byComponent',
          install: true,
          copy: false,
          verbose: true
        }
      }
    },
 
 
    // Concatenation
    concat: {
      bootstrap: {
        src: '<%= src.input.bootstrap.js %>',
        dest: '<%= src.output.bootstrap.js %>'
      },
    },
 
 
    // LESS
    less: {
      boldy: {
        options: {
          compress: true,
          cleancss: true,
          report: 'gzip',
          strictImports: true,
        },
        files: { '<%= src.output.boldy.css.screen %>': '<%= src.input.less %>'},
      },
      boldy_debug: {
          options: {
            compress: false,
            cleancss: false,
            report: 'none',
            strictImports: true,
          },
          files: { '<%= src.output.boldy.css.screen %>': '<%= src.input.less %>'},
      },
      bootstrap: {
        files: { '<%= src.output.bootstrap.css %>': '<%= src.input.bootstrap.less %>'}
      }
    },
 
 
    // Watcher
    watch: {
      boldy: {
        files: ['less/*.less'],
        tasks: ['less:boldy_debug'],
        options: {
          spawn: false,
        },
      },
    },
 
 
    // CSSmin
    cssmin: {
      boldy: {
        options: {
          report: 'gzip',
          banner: '<%= banner %>'
        },
        files: {
          '<%= src.output.boldy.css.indefero %>': '<%= src.input.indefero %>'
        }
      }
    },
 
 
    // Uglify
    uglify: {
      boldy: {
        options: {
          report: 'gzip',
          banner: '<%= banner %>'
        },
        files: {
          '<%= src.output.boldy.js %>': '<%= src.input.js %>',
        }
      }
    }
 
  });
 
 
  // Load plugins
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-bower-task');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
 
 
  // Callable tasks
  grunt.registerTask('default', ['boldy', 'cssmin', 'concat:bootstrap', 'uglify']);
  grunt.registerTask('w', ['watch:boldy']);
 
  grunt.registerTask('bootstrap', ['concat:bootstrap', 'less:bootstrap']);
  grunt.registerTask('boldy', ['less:boldy']);
 
  grunt.registerTask('full', ['bower', 'bootstrap', 'default']);
  grunt.registerTask('all', ['full']); // Alias
};

Tâche bower

Via le plugin grunt-bower-task.

Cette tâche est là pour exécuter Bower au travers de Grunt, notez que le plugin n'interprète pas le .bowerrc, je l'ai donc chargé moi même (bowerrc: grunt.file.readJSON('.bowerrc')) afin de passer les mêmes options à la tâche Grunt qu'à Bower.

Tâche Bootstrap

Via les plugins grunt-contrib-less & grunt-contrib-concat.

Le but de cette tâche est de ne pas utiliser la version distribuée de Bootstrap mais de reconstruire ma propre version. Pour celà,

  • je reconstruis le JavaScript à partir des sources et du plugin concat,
  • je recompile les CSS à partir d'une version allégée du bootstrap.less :
/* -- BEGIN LICENSE BLOCK ---------------------------------------
# This file is part of Boldy, a theme for Dotclear
#
# Theme by Site5 (http://www.s5themes.com)
# under a GPLv2 http://www.gnu.org/licenses/gpl-2.0.txt
# Ported on Dotclear by Guillaume Kulakowski (http://www.llaumgui.com)
#
# -- END LICENSE BLOCK ----------------------------------------- */
 
// Core variables and mixins
@import "../vendor/bootstrap/less/variables.less";
@import "../vendor/bootstrap/less/mixins.less";
 
// My override
@import "bootstrap_variables.less";
//@import "bootstrap_mixins.less";
 
// Reset
@import "../vendor/bootstrap/less/normalize.less";
@import "../vendor/bootstrap/less/print.less";
 
// Core CSS
@import "../vendor/bootstrap/less/scaffolding.less";
@import "../vendor/bootstrap/less/type.less";
@import "../vendor/bootstrap/less/code.less";
@import "../vendor/bootstrap/less/grid.less";
//@import "../vendor/bootstrap/less/tables.less";
@import "../vendor/bootstrap/less/forms.less";
@import "../vendor/bootstrap/less/buttons.less";
 
// Components
@import "../vendor/bootstrap/less/component-animations.less";
//@import "../vendor/bootstrap/less/glyphicons.less";
@import "../vendor/bootstrap/less/dropdowns.less";
//@import "../vendor/bootstrap/less/button-groups.less";
//@import "../vendor/bootstrap/less/input-groups.less";
@import "../vendor/bootstrap/less/navs.less";
@import "../vendor/bootstrap/less/navbar.less";
//@import "../vendor/bootstrap/less/breadcrumbs.less";
@import "../vendor/bootstrap/less/pagination.less";
@import "../vendor/bootstrap/less/pager.less";
//@import "../vendor/bootstrap/less/labels.less";
//@import "../vendor/bootstrap/less/badges.less";
//@import "../vendor/bootstrap/less/jumbotron.less";
@import "../vendor/bootstrap/less/thumbnails.less";
@import "../vendor/bootstrap/less/alerts.less";
//@import "../vendor/bootstrap/less/progress-bars.less";
//@import "../vendor/bootstrap/less/media.less";
@import "../vendor/bootstrap/less/list-group.less";
@import "../vendor/bootstrap/less/panels.less";
@import "../vendor/bootstrap/less/wells.less";
//@import "../vendor/bootstrap/less/close.less";
 
// Components w/ JavaScript
//@import "../vendor/bootstrap/less/modals.less";
@import "../vendor/bootstrap/less/tooltip.less";
//@import "../vendor/bootstrap/less/popovers.less";
@import "../vendor/bootstrap/less/carousel.less";
 
// Utility classes
@import "../vendor/bootstrap/less/utilities.less";
@import "../vendor/bootstrap/less/responsive-utilities.less";

Remarquez que j'utilise mes propres variables après celles de Bootstrap afin de les écraser et de modifier Bootstrap directement à la source.

Tâche Boldy

Via les plugins grunt-contrib-uglify, grunt-contrib-less & grunt-contrib-cssmin.

Comme en recompilant Bootstrap à partir des sources LESS j'ai adhéré au concept de LESS, j'ai réécrit le thème de mon blog en LESS.

Cette tâche boldy sert donc :

  • à générer le CSS minifié à partir des sources LESS (grunt-contrib-less),
  • à minifier la CSS pour mon thème indefero qui reste en CSS (grunt-contrib-cssmin),
  • et à minifier les Javascripts (grunt-contrib-uglify).

Tâche watch

Via le plugin grunt-contrib-watch.

Pour compiler du LESS en CSS, il y a 2 méthodes.

  • soit passer par le less.js qui va parser en JS les fichiers LESS à chaque chargement de page (2 à 3 secondes pour mon blog),
  • soit passer par une tâche watch dans Grunt, qui va écouter les modifications sur les fichiers LESS et recompiler un CSS.

C'est cette dernière solution que j'ai retenu et donc c'est à cela que sert la tâche watch.

En conclusion

Pour conclure, je dirais que la mise en place de ces outils (surtout pour la première fois) est certes chronophage, mais une fois que ça tourne, pour mettre à jour les libs (Bootstrap, jQuery, etc.), une seule ligne de commande suffit (grunt full). De plus, une fois Grunt et Bower en place (et maîtrisés), passer de CSS à LESS a été super simple.

Pour finir, je regrette presque que nodejs n'ait pas été inclus dans Fedora plus tôt car il propose de formidables outils indispensables aux développeurs (front) web.

Et pour voir ce que ça donne, une petite vidéo:

Grunt, Bower, LESS & Bootstrap

Guillaume Kulakowski
Dans mon dernier billet, j'avais évoqué mon engouement pour Bower, une solution de gestion de dépendances web. J'avais alors regretté le fait de ne pas pouvoir exécuter des tâches post-installation afin de retravailler la version distribuée de Bootstrap pour lalléger (comme on peut le faire ici). Comme j'en avais émis l'idée dans ce même billet, j'ai entrepris de ne plus utiliser Bower directement mais de lutiliser au travers de Grunt.

grunt-bower.png

Si vous ne connaissez pas encore Grunt, il s'agit d'un ordonnanceur au même titre que Maven, ant, ou encore Phing, mais basé sur nodejs et utilisant une syntaxe JavaScript.

Installation de Bower & Grunt sous Fedora 20

Après avoir installé nodejs et npm via yum, il faudra installer Bower et Grunt avec npm. En effet, Bower est absent des dépôts Fedora et Grunt est bien disponible mais sans grunt-cli, ce qui en enlève tout lintérêt...

sudo yum install npm -y
sudo npm install bower grunt grunt-cli -g

Notez au passage le fait que l'on fasse l'installation avec l'option -g pour avoir Grunt et Bower installés au niveau du système (/usr/lib/node_modules). Les autres installations se feront toujours à l'aide de npm mais sans cette option. Ceci permet de tout avoir à la racine du projet web, dans un répertoire node_modules (qu'il faudra exclure de la gestion de sources).

Voila, maintenant on rajoute un fichier packages.json et on installe les dépendances avec un npm install :

{
  "name": "Boldy",
  "version": "1.1.2",
  "description": "The Boldy theme for Dotclear",
  "repository": {
    "type": "git",
  },
  "author": "Guillaume Kulakowski",
  "homepage": "http://www.llaumgui.com",
  "devDependencies": {
    "bower": "latest",
    "grunt": "~0.4.2",
    "grunt-contrib-uglify": "latest",
    "grunt-contrib-concat": "latest",
    "grunt-contrib-less": "latest",
    "grunt-bower-task": "latest",
    "grunt-contrib-watch": "latest"
    "grunt-contrib-cssmin": "latest"
  }
}

J'ai maintenant un environnement de travail avec Bower et Grunt ainsi que les plugins nécessaires à mon projet.

Le fichier Gruntfile.js

La configuration des tâches Grunt passe par le fichier Gruntfile.js, j'ai mis le mien et vais en détailler les tâches :

module.exports = function(grunt) {
  'use strict';
 
  // Force use of Unix newlines
  grunt.util.linefeed = '\n';
 
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    bowerrc: grunt.file.readJSON('.bowerrc'),
 
    // Path configuration from Gruntfile.js
    dirs: {
      'vendor': '<%= bowerrc.directory %>',
      'bootstrap': {
        'js': '<%= dirs.vendor %>/bootstrap/js',
        'less': '<%= dirs.vendor %>/bootstrap/less'
      },
      'css': 'css',
      'less': 'less',
      'js': 'js'
    },
 
    src: {
      output: {
        'bootstrap': {
          'js': '<%= dirs.vendor %>/bootstrap/my/js/bootstrap.js',
          'css': '<%= dirs.vendor %>/bootstrap/my/css/bootstrap.css'
        },
        'boldy': {
          css: {
            'screen': '<%= dirs.css %>/screen.css',
            'indefero': '<%= dirs.css %>/indefero.css'
          },
          js: '<%= dirs.js %>/global.js'
        }
      },
 
      input: {
        bootstrap: {
          'js': [
            '<%= dirs.bootstrap.js %>/dropdown.js',
            '<%= dirs.bootstrap.js %>/tooltip.js',
            '<%= dirs.bootstrap.js %>/collapse.js',
            '<%= dirs.bootstrap.js %>/transition.js',
            '<%= dirs.bootstrap.js %>/carousel.js'
          ],
          'less': [
            '<%= dirs.less %>/bootstrap.less'
          ]
        },
        indefero: '<%= dirs.css %>/indefero.src.css',
        less: '<%= dirs.less %>/boldy_boot.less',
        js: [
          '<%= dirs.vendor %>/jquery-cookie/jquery.cookie.js',
          '<%= src.output.bootstrap.js %>',
          '<%= dirs.vendor %>/scroll-to-top/jquery.scrollToTop.min.js',
          '<%= dirs.js %>/js/post.js',
          '<%= dirs.vendor %>/async-gravatars/async-gravatars.js',
          '<%= dirs.vendor %>/jquery-colorbox/jquery.colorbox-min.js',
          '<%= dirs.vendor %>/nwxforms/src/nwxforms.js',
          '<%= dirs.js %>/boldy.js'
        ]
      },
    },
 
    // Banner
    banner: '/*!\n' +
              ' * Boldy for Dotclear v<%= pkg.version %>\n' +
              ' * Original theme by Site5 (http://www.s5themes.com)\n' +
              ' * Under a GPLv2 http://www.gnu.org/licenses/gpl-2.0.txt\n' +
              ' * Ported on Dotclear by <%= pkg.author %> (<%= pkg.homepage %>)\n' +
              ' * Copyright 2012-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
              ' */',
 
 
 
    /********************************** Task **********************************/
    // Bower
    bower: {
      install: {
        options: {
          targetDir: '<%= dirs.vendor %>',
          cleanTargetDir: true,
          layout: 'byComponent',
          install: true,
          copy: false,
          verbose: true
        }
      }
    },
 
 
    // Concatenation
    concat: {
      bootstrap: {
        src: '<%= src.input.bootstrap.js %>',
        dest: '<%= src.output.bootstrap.js %>'
      },
    },
 
 
    // LESS
    less: {
      boldy: {
        options: {
          compress: true,
          cleancss: true,
          report: 'gzip',
          strictImports: true,
        },
        files: { '<%= src.output.boldy.css.screen %>': '<%= src.input.less %>'},
      },
      boldy_debug: {
          options: {
            compress: false,
            cleancss: false,
            report: 'none',
            strictImports: true,
          },
          files: { '<%= src.output.boldy.css.screen %>': '<%= src.input.less %>'},
      },
      bootstrap: {
        files: { '<%= src.output.bootstrap.css %>': '<%= src.input.bootstrap.less %>'}
      }
    },
 
 
    // Watcher
    watch: {
      boldy: {
        files: ['less/*.less'],
        tasks: ['less:boldy_debug'],
        options: {
          spawn: false,
        },
      },
    },
 
 
    // CSSmin
    cssmin: {
      boldy: {
        options: {
          report: 'gzip',
          banner: '<%= banner %>'
        },
        files: {
          '<%= src.output.boldy.css.indefero %>': '<%= src.input.indefero %>'
        }
      }
    },
 
 
    // Uglify
    uglify: {
      boldy: {
        options: {
          report: 'gzip',
          banner: '<%= banner %>'
        },
        files: {
          '<%= src.output.boldy.js %>': '<%= src.input.js %>',
        }
      }
    }
 
  });
 
 
  // Load plugins
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-bower-task');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
 
 
  // Callable tasks
  grunt.registerTask('default', ['boldy', 'cssmin', 'concat:bootstrap', 'uglify']);
  grunt.registerTask('w', ['watch:boldy']);
 
  grunt.registerTask('bootstrap', ['concat:bootstrap', 'less:bootstrap']);
  grunt.registerTask('boldy', ['less:boldy']);
 
  grunt.registerTask('full', ['bower', 'bootstrap', 'default']);
  grunt.registerTask('all', ['full']); // Alias
};

Tâche bower

Via le plugin grunt-bower-task.

Cette tâche est là pour exécuter Bower au travers de Grunt, notez que le plugin n'interprète pas le .bowerrc, je l'ai donc chargé moi même (bowerrc: grunt.file.readJSON('.bowerrc')) afin de passer les mêmes options à la tâche Grunt qu'à Bower.

Tâche Bootstrap

Via les plugins grunt-contrib-less & grunt-contrib-concat.

Le but de cette tâche est de ne pas utiliser la version distribuée de Bootstrap mais de reconstruire ma propre version. Pour celà,

  • je reconstruis le JavaScript à partir des sources et du plugin concat,
  • je recompile les CSS à partir d'une version allégée du bootstrap.less :
/* -- BEGIN LICENSE BLOCK ---------------------------------------
# This file is part of Boldy, a theme for Dotclear
#
# Theme by Site5 (http://www.s5themes.com)
# under a GPLv2 http://www.gnu.org/licenses/gpl-2.0.txt
# Ported on Dotclear by Guillaume Kulakowski (http://www.llaumgui.com)
#
# -- END LICENSE BLOCK ----------------------------------------- */
 
// Core variables and mixins
@import "../vendor/bootstrap/less/variables.less";
@import "../vendor/bootstrap/less/mixins.less";
 
// My override
@import "bootstrap_variables.less";
//@import "bootstrap_mixins.less";
 
// Reset
@import "../vendor/bootstrap/less/normalize.less";
@import "../vendor/bootstrap/less/print.less";
 
// Core CSS
@import "../vendor/bootstrap/less/scaffolding.less";
@import "../vendor/bootstrap/less/type.less";
@import "../vendor/bootstrap/less/code.less";
@import "../vendor/bootstrap/less/grid.less";
//@import "../vendor/bootstrap/less/tables.less";
@import "../vendor/bootstrap/less/forms.less";
@import "../vendor/bootstrap/less/buttons.less";
 
// Components
@import "../vendor/bootstrap/less/component-animations.less";
//@import "../vendor/bootstrap/less/glyphicons.less";
@import "../vendor/bootstrap/less/dropdowns.less";
//@import "../vendor/bootstrap/less/button-groups.less";
//@import "../vendor/bootstrap/less/input-groups.less";
@import "../vendor/bootstrap/less/navs.less";
@import "../vendor/bootstrap/less/navbar.less";
//@import "../vendor/bootstrap/less/breadcrumbs.less";
@import "../vendor/bootstrap/less/pagination.less";
@import "../vendor/bootstrap/less/pager.less";
//@import "../vendor/bootstrap/less/labels.less";
//@import "../vendor/bootstrap/less/badges.less";
//@import "../vendor/bootstrap/less/jumbotron.less";
@import "../vendor/bootstrap/less/thumbnails.less";
@import "../vendor/bootstrap/less/alerts.less";
//@import "../vendor/bootstrap/less/progress-bars.less";
//@import "../vendor/bootstrap/less/media.less";
@import "../vendor/bootstrap/less/list-group.less";
@import "../vendor/bootstrap/less/panels.less";
@import "../vendor/bootstrap/less/wells.less";
//@import "../vendor/bootstrap/less/close.less";
 
// Components w/ JavaScript
//@import "../vendor/bootstrap/less/modals.less";
@import "../vendor/bootstrap/less/tooltip.less";
//@import "../vendor/bootstrap/less/popovers.less";
@import "../vendor/bootstrap/less/carousel.less";
 
// Utility classes
@import "../vendor/bootstrap/less/utilities.less";
@import "../vendor/bootstrap/less/responsive-utilities.less";

Remarquez que j'utilise mes propres variables après celles de Bootstrap afin de les écraser et de modifier Bootstrap directement à la source.

Tâche Boldy

Via les plugins grunt-contrib-uglify, grunt-contrib-less & grunt-contrib-cssmin.

Comme en recompilant Bootstrap à partir des sources LESS j'ai adhéré au concept de LESS, j'ai réécrit le thème de mon blog en LESS.

Cette tâche boldy sert donc :

  • à générer le CSS minifié à partir des sources LESS (grunt-contrib-less),
  • à minifier la CSS pour mon thème indefero qui reste en CSS (grunt-contrib-cssmin),
  • et à minifier les Javascripts (grunt-contrib-uglify).

Tâche watch

Via le plugin grunt-contrib-watch.

Pour compiler du LESS en CSS, il y a 2 méthodes.

  • soit passer par le less.js qui va parser en JS les fichiers LESS à chaque chargement de page (2 à 3 secondes pour mon blog),
  • soit passer par une tâche watch dans Grunt, qui va écouter les modifications sur les fichiers LESS et recompiler un CSS.

C'est cette dernière solution que j'ai retenu et donc c'est à cela que sert la tâche watch.

En conclusion

Pour conclure, je dirais que la mise en place de ces outils (surtout pour la première fois) est certes chronophage, mais une fois que ça tourne, pour mettre à jour les libs (Bootstrap, jQuery, etc.), une seule ligne de commande suffit (grunt full). De plus, une fois Grunt et Bower en place (et maîtrisés), passer de CSS à LESS a été super simple.

Pour finir, je regrette presque que nodejs n'ait pas été inclus dans Fedora plus tôt car il propose de formidables outils indispensables aux développeurs (front) web.

Et pour voir ce que ça donne, une petite vidéo:

Grunt, Bower, LESS & Bootstrap

Guillaume Kulakowski
Dans mon dernier billet, j'avais évoqué mon engouement pour Bower, une solution de gestion de dépendances web. J'avais alors regretté le fait de ne pas pouvoir exécuter des tâches post-installation afin de retravailler la version distribuée de Bootstrap pour lalléger (comme on peut le faire ici). Comme j'en avais émis l'idée dans ce même billet, j'ai entrepris de ne plus utiliser Bower directement mais de lutiliser au travers de Grunt.

grunt-bower.png

Si vous ne connaissez pas encore Grunt, il s'agit d'un ordonnanceur au même titre que Maven, ant, ou encore Phing, mais basé sur nodejs et utilisant une syntaxe JavaScript.

Installation de Bower & Grunt sous Fedora 20

Après avoir installé nodejs et npm via yum, il faudra installer Bower et Grunt avec npm. En effet, Bower est absent des dépôts Fedora et Grunt est bien disponible mais sans grunt-cli, ce qui en enlève tout lintérêt...

sudo yum install npm -y
sudo npm install bower grunt grunt-cli -g

Notez au passage le fait que l'on fasse l'installation avec l'option -g pour avoir Grunt et Bower installés au niveau du système (/usr/lib/node_modules). Les autres installations se feront toujours à l'aide de npm mais sans cette option. Ceci permet de tout avoir à la racine du projet web, dans un répertoire node_modules (qu'il faudra exclure de la gestion de sources).

Voila, maintenant on rajoute un fichier packages.json et on installe les dépendances avec un npm install :

{
  "name": "Boldy",
  "version": "1.1.2",
  "description": "The Boldy theme for Dotclear",
  "repository": {
    "type": "git",
  },
  "author": "Guillaume Kulakowski",
  "homepage": "http://www.llaumgui.com",
  "devDependencies": {
    "bower": "latest",
    "grunt": "~0.4.2",
    "grunt-contrib-uglify": "latest",
    "grunt-contrib-concat": "latest",
    "grunt-contrib-less": "latest",
    "grunt-bower-task": "latest",
    "grunt-contrib-watch": "latest"
    "grunt-contrib-cssmin": "latest"
  }
}

J'ai maintenant un environnement de travail avec Bower et Grunt ainsi que les plugins nécessaires à mon projet.

Le fichier Gruntfile.js

La configuration des tâches Grunt passe par le fichier Gruntfile.js, j'ai mis le mien et vais en détailler les tâches :

module.exports = function(grunt) {
  'use strict';
 
  // Force use of Unix newlines
  grunt.util.linefeed = '\n';
 
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    bowerrc: grunt.file.readJSON('.bowerrc'),
 
    // Path configuration from Gruntfile.js
    dirs: {
      'vendor': '<%= bowerrc.directory %>',
      'bootstrap': {
        'js': '<%= dirs.vendor %>/bootstrap/js',
        'less': '<%= dirs.vendor %>/bootstrap/less'
      },
      'css': 'css',
      'less': 'less',
      'js': 'js'
    },
 
    src: {
      output: {
        'bootstrap': {
          'js': '<%= dirs.vendor %>/bootstrap/my/js/bootstrap.js',
          'css': '<%= dirs.vendor %>/bootstrap/my/css/bootstrap.css'
        },
        'boldy': {
          css: {
            'screen': '<%= dirs.css %>/screen.css',
            'indefero': '<%= dirs.css %>/indefero.css'
          },
          js: '<%= dirs.js %>/global.js'
        }
      },
 
      input: {
        bootstrap: {
          'js': [
            '<%= dirs.bootstrap.js %>/dropdown.js',
            '<%= dirs.bootstrap.js %>/tooltip.js',
            '<%= dirs.bootstrap.js %>/collapse.js',
            '<%= dirs.bootstrap.js %>/transition.js',
            '<%= dirs.bootstrap.js %>/carousel.js'
          ],
          'less': [
            '<%= dirs.less %>/bootstrap.less'
          ]
        },
        indefero: '<%= dirs.css %>/indefero.src.css',
        less: '<%= dirs.less %>/boldy_boot.less',
        js: [
          '<%= dirs.vendor %>/jquery-cookie/jquery.cookie.js',
          '<%= src.output.bootstrap.js %>',
          '<%= dirs.vendor %>/scroll-to-top/jquery.scrollToTop.min.js',
          '<%= dirs.js %>/js/post.js',
          '<%= dirs.vendor %>/async-gravatars/async-gravatars.js',
          '<%= dirs.vendor %>/jquery-colorbox/jquery.colorbox-min.js',
          '<%= dirs.vendor %>/nwxforms/src/nwxforms.js',
          '<%= dirs.js %>/boldy.js'
        ]
      },
    },
 
    // Banner
    banner: '/*!\n' +
              ' * Boldy for Dotclear v<%= pkg.version %>\n' +
              ' * Original theme by Site5 (http://www.s5themes.com)\n' +
              ' * Under a GPLv2 http://www.gnu.org/licenses/gpl-2.0.txt\n' +
              ' * Ported on Dotclear by <%= pkg.author %> (<%= pkg.homepage %>)\n' +
              ' * Copyright 2012-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
              ' */',
 
 
 
    /********************************** Task **********************************/
    // Bower
    bower: {
      install: {
        options: {
          targetDir: '<%= dirs.vendor %>',
          cleanTargetDir: true,
          layout: 'byComponent',
          install: true,
          copy: false,
          verbose: true
        }
      }
    },
 
 
    // Concatenation
    concat: {
      bootstrap: {
        src: '<%= src.input.bootstrap.js %>',
        dest: '<%= src.output.bootstrap.js %>'
      },
    },
 
 
    // LESS
    less: {
      boldy: {
        options: {
          compress: true,
          cleancss: true,
          report: 'gzip',
          strictImports: true,
        },
        files: { '<%= src.output.boldy.css.screen %>': '<%= src.input.less %>'},
      },
      boldy_debug: {
          options: {
            compress: false,
            cleancss: false,
            report: 'none',
            strictImports: true,
          },
          files: { '<%= src.output.boldy.css.screen %>': '<%= src.input.less %>'},
      },
      bootstrap: {
        files: { '<%= src.output.bootstrap.css %>': '<%= src.input.bootstrap.less %>'}
      }
    },
 
 
    // Watcher
    watch: {
      boldy: {
        files: ['less/*.less'],
        tasks: ['less:boldy_debug'],
        options: {
          spawn: false,
        },
      },
    },
 
 
    // CSSmin
    cssmin: {
      boldy: {
        options: {
          report: 'gzip',
          banner: '<%= banner %>'
        },
        files: {
          '<%= src.output.boldy.css.indefero %>': '<%= src.input.indefero %>'
        }
      }
    },
 
 
    // Uglify
    uglify: {
      boldy: {
        options: {
          report: 'gzip',
          banner: '<%= banner %>'
        },
        files: {
          '<%= src.output.boldy.js %>': '<%= src.input.js %>',
        }
      }
    }
 
  });
 
 
  // Load plugins
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-bower-task');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
 
 
  // Callable tasks
  grunt.registerTask('default', ['boldy', 'cssmin', 'concat:bootstrap', 'uglify']);
  grunt.registerTask('w', ['watch:boldy']);
 
  grunt.registerTask('bootstrap', ['concat:bootstrap', 'less:bootstrap']);
  grunt.registerTask('boldy', ['less:boldy']);
 
  grunt.registerTask('full', ['bower', 'bootstrap', 'default']);
  grunt.registerTask('all', ['full']); // Alias
};

Tâche bower

Via le plugin grunt-bower-task.

Cette tâche est là pour exécuter Bower au travers de Grunt, notez que le plugin n'interprète pas le .bowerrc, je l'ai donc chargé moi même (bowerrc: grunt.file.readJSON('.bowerrc')) afin de passer les mêmes options à la tâche Grunt qu'à Bower.

Tâche Bootstrap

Via les plugins grunt-contrib-less & grunt-contrib-concat.

Le but de cette tâche est de ne pas utiliser la version distribuée de Bootstrap mais de reconstruire ma propre version. Pour celà,

  • je reconstruis le JavaScript à partir des sources et du plugin concat,
  • je recompile les CSS à partir d'une version allégée du bootstrap.less :
/* -- BEGIN LICENSE BLOCK ---------------------------------------
# This file is part of Boldy, a theme for Dotclear
#
# Theme by Site5 (http://www.s5themes.com)
# under a GPLv2 http://www.gnu.org/licenses/gpl-2.0.txt
# Ported on Dotclear by Guillaume Kulakowski (http://www.llaumgui.com)
#
# -- END LICENSE BLOCK ----------------------------------------- */
 
// Core variables and mixins
@import "../vendor/bootstrap/less/variables.less";
@import "../vendor/bootstrap/less/mixins.less";
 
// My override
@import "bootstrap_variables.less";
//@import "bootstrap_mixins.less";
 
// Reset
@import "../vendor/bootstrap/less/normalize.less";
@import "../vendor/bootstrap/less/print.less";
 
// Core CSS
@import "../vendor/bootstrap/less/scaffolding.less";
@import "../vendor/bootstrap/less/type.less";
@import "../vendor/bootstrap/less/code.less";
@import "../vendor/bootstrap/less/grid.less";
//@import "../vendor/bootstrap/less/tables.less";
@import "../vendor/bootstrap/less/forms.less";
@import "../vendor/bootstrap/less/buttons.less";
 
// Components
@import "../vendor/bootstrap/less/component-animations.less";
//@import "../vendor/bootstrap/less/glyphicons.less";
@import "../vendor/bootstrap/less/dropdowns.less";
//@import "../vendor/bootstrap/less/button-groups.less";
//@import "../vendor/bootstrap/less/input-groups.less";
@import "../vendor/bootstrap/less/navs.less";
@import "../vendor/bootstrap/less/navbar.less";
//@import "../vendor/bootstrap/less/breadcrumbs.less";
@import "../vendor/bootstrap/less/pagination.less";
@import "../vendor/bootstrap/less/pager.less";
//@import "../vendor/bootstrap/less/labels.less";
//@import "../vendor/bootstrap/less/badges.less";
//@import "../vendor/bootstrap/less/jumbotron.less";
@import "../vendor/bootstrap/less/thumbnails.less";
@import "../vendor/bootstrap/less/alerts.less";
//@import "../vendor/bootstrap/less/progress-bars.less";
//@import "../vendor/bootstrap/less/media.less";
@import "../vendor/bootstrap/less/list-group.less";
@import "../vendor/bootstrap/less/panels.less";
@import "../vendor/bootstrap/less/wells.less";
//@import "../vendor/bootstrap/less/close.less";
 
// Components w/ JavaScript
//@import "../vendor/bootstrap/less/modals.less";
@import "../vendor/bootstrap/less/tooltip.less";
//@import "../vendor/bootstrap/less/popovers.less";
@import "../vendor/bootstrap/less/carousel.less";
 
// Utility classes
@import "../vendor/bootstrap/less/utilities.less";
@import "../vendor/bootstrap/less/responsive-utilities.less";

Remarquez que j'utilise mes propres variables après celles de Bootstrap afin de les écraser et de modifier Bootstrap directement à la source.

Tâche Boldy

Via les plugins grunt-contrib-uglify, grunt-contrib-less & grunt-contrib-cssmin.

Comme en recompilant Bootstrap à partir des sources LESS j'ai adhéré au concept de LESS, j'ai réécrit le thème de mon blog en LESS.

Cette tâche boldy sert donc :

  • à générer le CSS minifié à partir des sources LESS (grunt-contrib-less),
  • à minifier la CSS pour mon thème indefero qui reste en CSS (grunt-contrib-cssmin),
  • et à minifier les Javascripts (grunt-contrib-uglify).

Tâche watch

Via le plugin grunt-contrib-watch.

Pour compiler du LESS en CSS, il y a 2 méthodes.

  • soit passer par le less.js qui va parser en JS les fichiers LESS à chaque chargement de page (2 à 3 secondes pour mon blog),
  • soit passer par une tâche watch dans Grunt, qui va écouter les modifications sur les fichiers LESS et recompiler un CSS.

C'est cette dernière solution que j'ai retenu et donc c'est à cela que sert la tâche watch.

En conclusion

Pour conclure, je dirais que la mise en place de ces outils (surtout pour la première fois) est certes chronophage, mais une fois que ça tourne, pour mettre à jour les libs (Bootstrap, jQuery, etc.), une seule ligne de commande suffit (grunt full). De plus, une fois Grunt et Bower en place (et maîtrisés), passer de CSS à LESS a été super simple.

Pour finir, je regrette presque que nodejs n'ait pas été inclus dans Fedora plus tôt car il propose de formidables outils indispensables aux développeurs (front) web.

Et pour voir ce que ça donne, une petite vidéo:

Bower pour gérer les dépendances du thème de mon blog

Guillaume Kulakowski

C'est à la lecture de cet excellent article de Raphaël Goetter (dont le livre "CSS avancées vers HTML5 et CSS3" fut un de mes livres de chevet) sur Alsacreations que j'ai décidé de mettre en place Bower pour gérer les dépendances du thème de mon blog.

Pour ceux qui ne connaissent pas (encore) Bower et qui n'ont pas eu la curiosité de cliquer sur les liens ci-dessus: sachez juste que Bower est un gestionnaire de paquets pour le web (JS, CSS, etc). On pourrait même faire le raccourci en disant que Bower est au web ce que Composer est à PHP.

Les avantages immédiats que j'y trouve :

  • Un simple bower update et je mets à jour toutes les librairies tierces.
  • Le cloisonnement entre mon code et le code tiers. En effet, ce dernier se trouve dans un répertoire séparé: vendor (les habitudes de symfony2 ;-)).
  • Comme au travail je fais beaucoup de Symfony2 et d'eZ Publish 5, j'utilise pas mal composer, avec Bower je ne suis donc pas perdu.

Les inconvénients que j'y trouve :

  • Bower ne fait que récupérer les dépendances. Il ne permet pas (encore), comme (entre autre) Composer, de lancer des scripts post-installation ou post-mise-à-jour.
  • Bower récupère Bootstrap dans son intégralité alors que moi, j'aimerais l'optimiser et en réduire le poids.

Avant de pouvoir passer en production cette nouvelle version de mon blog, qui se doit d'être ISO avec la précédente, il me reste donc à régler quelques problèmes :

  • Optimiser ou reconstruire Bootstrap après l'avoir récupéré.
  • Minifier tout mon code.
  • Réfléchir à comment le pousser en production.
    En effet, Bower tournant sous node.js, je n'ai pas spécialement envie de déployer node sur mon serveur. Jusquà présent jutilisais GIT pour déployer le code source et je lançais juste un script shell pour minifier CSS et JS via YUI Compressor. Là je pense que je vais, soit devoir héberger les scripts minifiés sur GIT (ce qui n'est pas une bonne pratique) soit mettre en place un Jenkins (pour la construction du paquet) et un Capistrano (pour le déploiement). Autant au boulot le couple Jenkins/Capistrano m'est indispensable autant là pour déployer une fois de temps en temps une nouvelle version de mon blog, je pense que je vais opter pour les fichiers dans GIT.

Pour ceux que ça intéressent, ma configuration Bower :

# cat .bowerrc
{
    "directory": "vendor"
}
# cat bower.json
{
    "name": "Boldy",
    "version": "1.1",
    "main": [
        "css/screen.css",
        "css/indefero.css",
        "js/global.js"
    ],
    "ignore": [
        ".jshintrc",
        "**/*.txt"
    ],
    "private": true,
    "dependencies": {
        "jquery": "~1.*",
        "bootstrap": "3.0.*",
        "jquery.browser": "latest",
        "jquery-colorbox": "latest",
        "jquery-cookie": "latest",
        "scroll-to-top": "latest",
        "headjs": "latest"
    }
}

Bower pour gérer les dépendances du thème de mon blog

Guillaume Kulakowski

C'est à la lecture de cet excellent article de Raphaël Goetter (dont le livre "CSS avancées vers HTML5 et CSS3" fut un de mes livres de chevet) sur Alsacreations que j'ai décidé de mettre en place Bower pour gérer les dépendances du thème de mon blog.

Pour ceux qui ne connaissent pas (encore) Bower et qui n'ont pas eu la curiosité de cliquer sur les liens ci-dessus: sachez juste que Bower est un gestionnaire de paquets pour le web (JS, CSS, etc). On pourrait même faire le raccourci en disant que Bower est au web ce que Composer est à PHP.

Les avantages immédiats que j'y trouve :

  • Un simple bower update et je mets à jour toutes les librairies tierces.
  • Le cloisonnement entre mon code et le code tiers. En effet, ce dernier se trouve dans un répertoire séparé: vendor (les habitudes de symfony2 ;-)).
  • Comme au travail je fais beaucoup de Symfony2 et d'eZ Publish 5, j'utilise pas mal composer, avec Bower je ne suis donc pas perdu.

Les inconvénients que j'y trouve :

  • Bower ne fait que récupérer les dépendances. Il ne permet pas (encore), comme (entre autre) Composer, de lancer des scripts post-installation ou post-mise-à-jour.
  • Bower récupère Bootstrap dans son intégralité alors que moi, j'aimerais l'optimiser et en réduire le poids.

Avant de pouvoir passer en production cette nouvelle version de mon blog, qui se doit d'être ISO avec la précédente, il me reste donc à régler quelques problèmes :

  • Optimiser ou reconstruire Bootstrap après l'avoir récupéré.
  • Minifier tout mon code.
  • Réfléchir à comment le pousser en production.
    En effet, Bower tournant sous node.js, je n'ai pas spécialement envie de déployer node sur mon serveur. Jusquà présent jutilisais GIT pour déployer le code source et je lançais juste un script shell pour minifier CSS et JS via YUI Compressor. Là je pense que je vais, soit devoir héberger les scripts minifiés sur GIT (ce qui n'est pas une bonne pratique) soit mettre en place un Jenkins (pour la construction du paquet) et un Capistrano (pour le déploiement). Autant au boulot le couple Jenkins/Capistrano m'est indispensable autant là pour déployer une fois de temps en temps une nouvelle version de mon blog, je pense que je vais opter pour les fichiers dans GIT.

Pour ceux que ça intéressent, ma configuration Bower :

# cat .bowerrc
{
    "directory": "vendor"
}
# cat bower.json
{
    "name": "Boldy",
    "version": "1.1",
    "main": [
        "css/screen.css",
        "css/indefero.css",
        "js/global.js"
    ],
    "ignore": [
        ".jshintrc",
        "**/*.txt"
    ],
    "private": true,
    "dependencies": {
        "jquery": "~1.*",
        "bootstrap": "3.0.*",
        "jquery.browser": "latest",
        "jquery-colorbox": "latest",
        "jquery-cookie": "latest",
        "scroll-to-top": "latest",
        "headjs": "latest"
    }
}

Bower pour gérer les dépendances du thème de mon blog

Guillaume Kulakowski

C'est à la lecture de cet excellent article de Raphaël Goetter (dont le livre "CSS avancées vers HTML5 et CSS3" fut un de mes livres de chevet) sur Alsacreations que j'ai décidé de mettre en place Bower pour gérer les dépendances du thème de mon blog.

Pour ceux qui ne connaissent pas (encore) Bower et qui n'ont pas eu la curiosité de cliquer sur les liens ci-dessus: sachez juste que Bower est un gestionnaire de paquets pour le web (JS, CSS, etc). On pourrait même faire le raccourci en disant que Bower est au web ce que Composer est à PHP.

Les avantages immédiats que j'y trouve :

  • Un simple bower update et je mets à jour toutes les librairies tierces.
  • Le cloisonnement entre mon code et le code tiers. En effet, ce dernier se trouve dans un répertoire séparé: vendor (les habitudes de symfony2 ;-)).
  • Comme au travail je fais beaucoup de Symfony2 et d'eZ Publish 5, j'utilise pas mal composer, avec Bower je ne suis donc pas perdu.

Les inconvénients que j'y trouve :

  • Bower ne fait que récupérer les dépendances. Il ne permet pas (encore), comme (entre autre) Composer, de lancer des scripts post-installation ou post-mise-à-jour.
  • Bower récupère Bootstrap dans son intégralité alors que moi, j'aimerais l'optimiser et en réduire le poids.

Avant de pouvoir passer en production cette nouvelle version de mon blog, qui se doit d'être ISO avec la précédente, il me reste donc à régler quelques problèmes :

  • Optimiser ou reconstruire Bootstrap après l'avoir récupéré.
  • Minifier tout mon code.
  • Réfléchir à comment le pousser en production.
    En effet, Bower tournant sous node.js, je n'ai pas spécialement envie de déployer node sur mon serveur. Jusquà présent jutilisais GIT pour déployer le code source et je lançais juste un script shell pour minifier CSS et JS via YUI Compressor. Là je pense que je vais, soit devoir héberger les scripts minifiés sur GIT (ce qui n'est pas une bonne pratique) soit mettre en place un Jenkins (pour la construction du paquet) et un Capistrano (pour le déploiement). Autant au boulot le couple Jenkins/Capistrano m'est indispensable autant là pour déployer une fois de temps en temps une nouvelle version de mon blog, je pense que je vais opter pour les fichiers dans GIT.

Pour ceux que ça intéressent, ma configuration Bower :

# cat .bowerrc
{
    "directory": "vendor"
}
# cat bower.json
{
    "name": "Boldy",
    "version": "1.1",
    "main": [
        "css/screen.css",
        "css/indefero.css",
        "js/global.js"
    ],
    "ignore": [
        ".jshintrc",
        "**/*.txt"
    ],
    "private": true,
    "dependencies": {
        "jquery": "~1.*",
        "bootstrap": "3.0.*",
        "jquery.browser": "latest",
        "jquery-colorbox": "latest",
        "jquery-cookie": "latest",
        "scroll-to-top": "latest",
        "headjs": "latest"
    }
}

Bower pour gérer les dépendances du thème de mon blog

Guillaume Kulakowski

C'est à la lecture de cet excellent article de Raphaël Goetter (dont le livre "CSS avancées vers HTML5 et CSS3" fut un de mes livres de chevet) sur Alsacreations que j'ai décidé de mettre en place Bower pour gérer les dépendances du thème de mon blog.

Pour ceux qui ne connaissent pas (encore) Bower et qui n'ont pas eu la curiosité de cliquer sur les liens ci-dessus: sachez juste que Bower est un gestionnaire de paquets pour le web (JS, CSS, etc). On pourrait même faire le raccourci en disant que Bower est au web ce que Composer est à PHP.

Les avantages immédiats que j'y trouve :

  • Un simple bower update et je mets à jour toutes les librairies tierces.
  • Le cloisonnement entre mon code et le code tiers. En effet, ce dernier se trouve dans un répertoire séparé: vendor (les habitudes de symfony2 ;-)).
  • Comme au travail je fais beaucoup de Symfony2 et d'eZ Publish 5, j'utilise pas mal composer, avec Bower je ne suis donc pas perdu.

Les inconvénients que j'y trouve :

  • Bower ne fait que récupérer les dépendances. Il ne permet pas (encore), comme (entre autre) Composer, de lancer des scripts post-installation ou post-mise-à-jour.
  • Bower récupère Bootstrap dans son intégralité alors que moi, j'aimerais l'optimiser et en réduire le poids.

Avant de pouvoir passer en production cette nouvelle version de mon blog, qui se doit d'être ISO avec la précédente, il me reste donc à régler quelques problèmes :

  • Optimiser ou reconstruire Bootstrap après l'avoir récupéré.
  • Minifier tout mon code.
  • Réfléchir à comment le pousser en production.
    En effet, Bower tournant sous node.js, je n'ai pas spécialement envie de déployer node sur mon serveur. Jusquà présent jutilisais GIT pour déployer le code source et je lançais juste un script shell pour minifier CSS et JS via YUI Compressor. Là je pense que je vais, soit devoir héberger les scripts minifiés sur GIT (ce qui n'est pas une bonne pratique) soit mettre en place un Jenkins (pour la construction du paquet) et un Capistrano (pour le déploiement). Autant au boulot le couple Jenkins/Capistrano m'est indispensable autant là pour déployer une fois de temps en temps une nouvelle version de mon blog, je pense que je vais opter pour les fichiers dans GIT.

Pour ceux que ça intéressent, ma configuration Bower :

# cat .bowerrc
{
    "directory": "vendor"
}
# cat bower.json
{
    "name": "Boldy",
    "version": "1.1",
    "main": [
        "css/screen.css",
        "css/indefero.css",
        "js/global.js"
    ],
    "ignore": [
        ".jshintrc",
        "**/*.txt"
    ],
    "private": true,
    "dependencies": {
        "jquery": "~1.*",
        "bootstrap": "3.0.*",
        "jquery.browser": "latest",
        "jquery-colorbox": "latest",
        "jquery-cookie": "latest",
        "scroll-to-top": "latest",
        "headjs": "latest"
    }
}

Barcamp "Performances web"

Guillaume Kulakowski

A mon travail, on essai de faire une fois par mois un déjeuner autour d'une thématique. J'étais déjà intervenu il y a quelques mois pour présenter GIT, avec pour sanction immédiate que GIT soit devenu notre gestionnaire de sources par défaut et certain de nos grosses TMA ont déjà migré dessus.

Bref, ce mois ci la thématique était autour des performances web avec une présentation dense (plus de 1H30) ayant pour but de présenter les bonnes pratiques à nos nouveaux membres (c'est comme ça qu'on appel les salariés chez CGI) ainsi que de faire une piqure de rappel aux anciens et peut être leur rappeler pourquoi.

La présentation sous reveals est disponible sous licence Creative Commons Attribution-ShareAlike 4.0 International : Performances web.

Barcamp "Performances web"

Guillaume Kulakowski

A mon travail, on essai de faire une fois par mois un déjeuner autour d'une thématique. J'étais déjà intervenu il y a quelques mois pour présenter GIT, avec pour sanction immédiate que GIT soit devenu notre gestionnaire de sources par défaut et certain de nos grosses TMA ont déjà migré dessus.

Bref, ce mois ci la thématique était autour des performances web avec une présentation dense (plus de 1H30) ayant pour but de présenter les bonnes pratiques à nos nouveaux membres (c'est comme ça qu'on appel les salariés chez CGI) ainsi que de faire une piqure de rappel aux anciens et peut être leur rappeler pourquoi.

La présentation sous reveals est disponible sous licence Creative Commons Attribution-ShareAlike 4.0 International : Performances web.

Barcamp "Performances web"

Guillaume Kulakowski

A mon travail, on essai de faire une fois par mois un déjeuner autour d'une thématique. J'étais déjà intervenu il y a quelques mois pour présenter GIT, avec pour sanction immédiate que GIT soit devenu notre gestionnaire de sources par défaut et certain de nos grosses TMA ont déjà migré dessus.

Bref, ce mois ci la thématique était autour des performances web avec une présentation dense (plus de 1H30) ayant pour but de présenter les bonnes pratiques à nos nouveaux membres (c'est comme ça qu'on appel les salariés chez CGI) ainsi que de faire une piqure de rappel aux anciens et peut être leur rappeler pourquoi.

La présentation sous reveals est disponible sous licence Creative Commons Attribution-ShareAlike 4.0 International : Performances web.

Barcamp "Performances web"

Guillaume Kulakowski

A mon travail, on essai de faire une fois par mois un déjeuner autour d'une thématique. J'étais déjà intervenu il y a quelques mois pour présenter GIT, avec pour sanction immédiate que GIT soit devenu notre gestionnaire de sources par défaut et certain de nos grosses TMA ont déjà migré dessus.

Bref, ce mois ci la thématique était autour des performances web avec une présentation dense (plus de 1H30) ayant pour but de présenter les bonnes pratiques à nos nouveaux membres (c'est comme ça qu'on appel les salariés chez CGI) ainsi que de faire une piqure de rappel aux anciens et peut être leur rappeler pourquoi.

La présentation sous reveals est disponible sous licence Creative Commons Attribution-ShareAlike 4.0 International : Performances web.

FluxSphinx, l'intégration de Sphinx dans FluxBB

Guillaume Kulakowski

Il y a de cela quelques mois, nous avons rencontré des montées en charge sur Borsalino (l'ancien serveur de Fedora-Fr). Après enquête, il s'est avéré que la recherche de certains mots (ceux qui remontaient le plus de résultats) sur les forums faisait planter les sites en entrainant une charge sur le serveur MySQL. La sentence est vite tombée et nous avons été contraints de couper la recherche native sur les forums de Fedora-Fr et de basculer sur Google Custom Search Engine.

Avec l'arrivée de Stetson, le nouveau serveur mis à disposition par nos amis d'Ikoula, la question de remettre la recherche en place s'est posée. Cependant, je trouvais frustrant de répondre à un problème de conception (la recherche native de FluxBB bien que très efficace n'est pas adaptée aux grosses volumétries) par une course à l'armement (la RAM dans notre cas). Bref, je travaillais depuis quelques temps à limplémentation de Sphinx pour FluxBB sous le nom de code FluxSphinx. Et depuis ce long week-end de Toussaint, FluxSphinx est en production sur les forums de Fedora-Fr et le code est disponible sur le site du projet.

A noter que la configuration permet d'inclure la librairie PECL compilée plus efficiente que l'API en php (que vous pouvez également utiliser).

Pour le moment FluxSphinx est Iso fonctionnel avec la recherche native de FluxBB, seul le tri par pertinence ainsi que le récapitulatif dans le résultat de la recherche le distingue de la recherche native.

Cette version 0.9 donnera naissance rapidement à une v1.0 lorsque les bugs éventuels auront été remontés et corrigés. Ensuite devrait arriver une version 1.1 avec l'arrivée de facettes.

Publication de Gauffr 0.9

Guillaume Kulakowski

Après pas mal de travail, la version 0.9 de Gauffr vient de voir le jour. Cette version préfigure à peu de chose près ce que sera la version 1.0 une fois que les derniers ajustements seront réalisés.

Ecran de connection de Gauffr

Pour énième rappel, Gauffr est un système permettant de connecter des applications diverses appelées GauffrSlave qui vont utiliser le couple "login / mot de passe" issu d'une seule application déjà existante appelée GauffrMaster. Gauffr vous offre donc un niveau d'abstraction entre vos applications GauffrSlave et votre application maitresse que vous pouvez changer sans avoir à tout re-développer.

Les nouveautés de cette 0.9 sont essentiellement centrées autour de la GauffrAdmin qui permet de manipuler certaines données telles que les informations étendues qui vous permettent d'enrichir vos données maitresses sans en altérer le modèle de données ni le code.

Informations étendues sur les utilisateurs

Pour le moment, ces informations étendues sont essentiellement orientées vers les logins alternatifs, par exemple, si comme pour Fedora-Fr vous avez un login de type forums (llaumgui dans mon cas) et un login pour les wiki (GuillaumeKulakowski). A terme, j'envisage de stocker les informations OpenID mais surtout de permettre d'étendre ces données à partir d'un fichier de configuration.

Une autre fonctionnalité de la GauffrAdmin est de permettre de configurer les droits utilisateurs. Vous pouvez par exemple permettre à vos membres qui en ont le droit et seulement eux de se connecter au wiki, les plugins mwGauffr créera automatiquement le compte à la première connexion.

Droits utilisateur

Migration de mon blog en HTML5

Guillaume Kulakowski

Ça fait un petit moment que je n'avais pas travaillé sur mon blog... Il faut dire que la v5 de Fedora-Fr m'a pris pas mal de temps. Mais maintenant que c'est à peu près fini, je me suis lancé dans le portage du thème de mon blog en HTML5.

Au programme :

  • utilisation des "role" : banner, main, complementary, etc...
  • utilisation des nouvelles balises : section, article, header, footer
  • Formulaire : aria, placeholder (le truc le plus visible), etc...

Pour moi les avantages de l'HTML5 sont :

  • La sémantique web grâce aux nouvelles balises et au rôles. Une meilleure sémantique est selon moi gage d'un meilleur référencement.
  • La mobilité, qui fera l'objet de mon prochain travail...

Pour réaliser ce portage, je me suis basé sur ces différentes ressources :

J'ai également profité de cette mise à jour pour :

  • Rajouter la validation des formulaires en JavaScript,
  • Passer les icônes de réseaux sociaux en CSS sprite,
  • Rajouter Linkedin,
  • Migrer sous jQuery 1.5 et utiliser le CDN de Google,
  • Améliorer l'interface d'administration du thème de ce blog (cf capture).

Configuration du thème Emplode HTML5

llaumgui.com sous jQuery

Guillaume Kulakowski

Après plusieurs années de résistance à vouloir faire tourner Dotclear avec MooTools, j'ai décidé de raccrocher les gants. Ce blog tourne à présent sous jQuery, la solution de framework Javascript officiellement retenue par Dotclear. Vraisemblablement, je ne devrais plus trop maintenir mon script dcRemember permettant de faire tourner les fonctions JS de bases de dotclear sous MooTools.

Mais pourquoi lâcher MooTools alors que c'est le meilleur framework JS au monde (si ça c'est pas un troll ;-)) ? La raison est simplement qu'avec l'intégration de jQuery de plus en plus forte dans eZ Publish, je risque d'utiliser de moins en moins MooTools. J'avais donc besoin d'un labo sous jQuery et l'un des buts premiers de ce blog est justement de servir de labo.