Iconfont : génération via Gulp.js

Mise à jour du 25/06/2015 : multiples modifications suite aux mises à jour de gulp-iconfont.

Bonjour à tous !
C’est mon premier article sur le blog de UX-Republic et je vais vous expliquer comment je fais pour générer une iconfont à partir de fichiers SVG de façon rapide et la moins rébarbative possible en utilisant Gulp.js.
iconfont Gulp.js

Pourquoi ?

Avant d’utiliser Gulp.js pour générer une iconfont, je passais par le service IcoMoon App.
Cela fonctionne très bien mais de nombreuses étapes sont nécessaires avant de voir apparaître un icône s’afficher sur son navigateur :

  • aller sur la page,
  • importer les SVG (parcourir ses dossiers sur son ordinateur),
  • sélectionner ses icônes,
  • cliquer sur « Generate Font »,
  • cliquer sur« Download »,
  • décompresser l’archive,
  • déplacer les fichiers de polices,
  • copier/coller le CSS.

Et pour peu qu’on ait oublié quelque chose ou que le fichier SVG ne soit pas correct… il faut tout recommencer.
Le but de cet exercice réalisé avec Gulp.js est de rendre automatique l’ajout d’un icône à son iconfont. Que la seule action à faire soit de déplacer son fichier SVG dans un dossier et d’exécuter une seule commande dans le terminal pour lancer la génération de notre iconfont (font et CSS).

Pré-requis

Tout d’abord il va falloir installer quelques outils sur votre ordinateur pour pouvoir générer votre iconfont.

Node.js

Logo Node JSNode.js est une plateforme logicielle orientée réseau. Il permet d’utiliser du JavaScript ailleurs que dans un navigateur web.
Il vous faut télécharger l’installateur et l’exécuter comme pour installer n’importe quel programme. Vous pouvez d’ores et déjà le faire en suivant le lien suivant : https://nodejs.org/download/.

Gulp.js

Logo Gulp JsGulp.js est un programme développé comme son nom l’indique en JavaScript (extension .js). C’est lui qui va nous permettre d’exécuter nos tâches.
Pour l’installer le plus facilement possible, nous allons le faire en ligne de commande à l’aide d’un terminal.

Configuration du projet

Commençons par créer un dossier dans lequel nous allons mettre tous les fichiers et installer les modules dont nous aurons besoin à la génération de notre iconfont.
Voici la structure que je vous propose :

iconfont_project
    \css
    \fonts
        \custom
    \icons
    \scss
        \templates
            _icons.scss
        _icons.scss
        fonts.scss
        main.scss
    gulpfile.js
    index.html

Ouvrez un terminal et placez-vous dans le dossier du projet.
Il faut créer un fichier package.json qui aura pour but de regrouper toutes les informations du projet (nom, version, modules utilisés, etc.).
Pour cela, tapez la commande suivante :

npm init

Installer Gulp.js

Pour installer Gulp.js, tapez la commande :

npm install --save-dev gulp

Installer les modules Gulp.js

Nous avons besoin de plusieurs modules pour notre projet :

Pour les installer, tapez cette commande :

npm install --save-dev gulp-sass gulp-iconfont gulp-consolidate lodash

Vous devriez voir apparaître un nouveau dossier intitulé « node_modules », c’est là où Gulp.js et ses modules sont installés.

Écrire le Gulpfile

Le fichier gulpfile.js est le fichier où l’on va écrire nos tâches qui vont nous servir à la génération des fichiers de police et du CSS.
On commence par appeler nos librairies précédemment téléchargées :

var gulp = require('gulp')
  , sass = require('gulp-sass')
  , iconfont = require('gulp-iconfont')
  , consolidate = require('gulp-consolidate');

On écrit notre fonction iconfont (vous retrouverez le code commenté sur GitHub à la fin de l’article) :

gulp.task('iconfont', function () {
  gulp.src('icons/**/*.svg')
    .pipe(iconfont({
      fontName: 'custom'
    , centerHorizontally: true
    , normalize: true
    , appendUnicode: true
    }))
    .on('glyphs', function (glyphs) {
      gulp.src('scss/templates/_icons.scss')
        .pipe(consolidate('lodash', {
          glyphs: glyphs
        , fontName: 'custom'
        , fontPath: '../fonts/custom/'
        , className: 'icon'
        }))
        .pipe(gulp.dest('scss'));
    })
    .pipe(gulp.dest('fonts/custom'));
});

Une deuxième fonction intitulée « sass » pour compiler notre CSS :

gulp.task('sass', function () {
  gulp.src('scss/**/*.scss')
    .pipe(sass({
      indentWidth: 4
    , outputStyle: 'expanded'
    }))
    .pipe(gulp.dest('css'));
});

Gulp.js requière une fonction par défaut qu’on doit nommer default :

gulp.task('default', ['sass'], function () {
  gulp.watch('scss/**/*.scss', ['sass']);
});

Dans cette fonction on exécute la fonction « sass » puis on dit à Gulp.js de regarder si un de nos fichiers Sass est modifié. Si oui, il exécutera à nouveau la fonction « sass ».

Création du template

Le template est un fichier Sass dans lequel on va mettre les variables des informations que nous avons écrit dans notre fichier gulpfile.js à savoir le nom de notre police, le chemin de nos fichiers de police, etc.
On va aussi récupérer le tableau où sont stockés les “code points”. C’est le code qui sera inséré dans le content CSS.
Remarque : le script reprendra le nom du SVG que vous lui aurez donné.
Voici un exemple de ce qui sera généré en CSS si je nomme mon fichier SVG « myicon.svg » :

.icon-myicon:before {
    content: "\E001";
}

Nous allons écrire notre template dans le dossier scss/templates.
Commençons par écrire le @font-face qui va appeler notre iconfont :

@font-face {
    font-family: '<%= fontName %>';
    font-weight: normal;
    font-style: normal;
    src: url('<%= fontPath %><%= fontName %>.eot');
    src: url('<%= fontPath %><%= fontName %>.woff2') format('woff2'),
         url('<%= fontPath %><%= fontName %>.woff') format('woff'),
         url('<%= fontPath %><%= fontName %>.ttf') format('truetype'),
         url('<%= fontPath %><%= fontName %>.eot?#iefix') format('embedded-opentype');
}

Tout ce qui est contenu dans « <%= » et « %> » est en réalité du code JavaScript. « fontName » et « fontPath » sont des variables qui reprennent les paramètres que nous avons écrit dans la méthode « consolidate » de notre tâche « iconfont » situé dans notre gulpfile.js.
Nous écrivons ensuite la classe principale dans laquelle nous allons appeler la police via font-family ainsi que les styles propres aux polices que nous initialisons à la valeur par défaut pour annuler les styles qui pourraient être appliqués sur les balises parentes où se trouverait notre icône :

.<%= className %>[class^="<%= className %>-"],
.<%= className %>[class*=" <%= className %>-"] {
    display: inline-block;
    font-family: '<%= fontName %>';
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    font-style: normal;
    font-variant: normal;
    font-weight: normal;
    line-height: 1;
    text-transform: none;
}

Les deux dernières propriétés servent à déclencher l’effet ClearType dans le but d’avoir un meilleur rendu en activant l’antialiasing.
Nous allons ensuite créer une boucle pour construire une map que nous nommerons « icons ».
Une map est un type de données en Sass qui permet de structurer les données par couple clé / valeur.

$icons: (
    <%= glyphs.map(function(glyph) {
        return glyph.name + ': '\' + '\\' + glyph.unicode[0].charCodeAt(0).toString(16).toUpperCase() + ''\'
    }).join(',\n ') %>
);

« glyphs » (variable JavaScript, voir fichier gulpfile.js) est un tableau contenant des objets et pour chacun d’entre eux nous allons exécuter une fonction qui va nous retourner le nom du glyphe (glyph.name) qui est le nom du fichier SVG que vous lui aurez donné. Ces noms seront les clés de la map Sass.
Pour les valeurs de la map on retourne les code points (glyph.codepoint) que nous convertissons en hexadécimal et que nous transformons en majuscule.
Une fois la map générée cela donne ceci :

$icons: (
    antenna: '\E001',
    heart: '\E002'
);

Et pour finir nous créons une boucle (en langage Sass cette fois) qui servira à lire chaque élément de notre map et générer le CSS :

@each $name, $icon in $icons {
    .<%= className %>-#{$name}:before {
        content: $icon;
    }
}

Dans la boucle each, la première variable « name » contient les clés de la map et la deuxième « icon » contient les valeurs.
On écrit ensuite le CSS. Dans <%= className %> nous auront la valeur « icon » (assignée dans le fichier gulpfile.js).
#{$name} est notre clé avec le nom de le classe.
$icon est notre valeur avec le code point.
Pourquoi #{$name} et pas simplement $name ?
On écrit une variable à l’intérieur d’une chaîne de caractère et on utilise ici ce qu’on appelle l’interpolation.
Lorsque nous exécuterons notre tâche « iconfont », cela va prendre le fichier sass/templates/_icons.scss, exécuter le code JavaScript et générer le fichier sass/_icons.scss. C’est la tâche « sass » qui va générer le CSS.

Exécuter Gulp.js pour générer l’iconfont

Pour générer les fichiers de police et le SCSS, il faut exécuter notre tâche « iconfont » comme ceci :

gulp iconfont

Pour compiler le code Sass en CSS, nous allons exécuter notre fonction « default » :

gulp default

Gulp.js a simplifié les choses, on peut omettre le mot « default », cela va quand même exécuter notre tâche par défaut :

gulp

Utiliser notre nouvelle icône

Si on reprend l’exemple plus haut, pour afficher notre icône il faut écrire une balise avec la classe icon qui est la classe principale et la classe icon-myicon qui contient le content.
Exemple :

<i class="icon icon-myicon"></i>

Conclusion

Il faut un peu de temps pour tout mettre en place mais au cours d’un projet, ajouter un icône dans sa web font se fait en quelques secondes.
Tous les fichiers sont sur le GitHub de UX-Republic, vous pourrez les télécharger à cette adresse : https://github.com/ux-republic/gulp-icon-font.
N’hésitez pas à poser vos questions dans les commentaires.