Benoît Courtine



    Navigation
     » Accueil
     » A propos
     » Mentions légales
     » XML Feed

    Adaptation d’un thème Jekyll pour Asciidoc

    05 May 2017 (MAJ le 22/01/2019 à 21:14) » jekyll, asciidoc

    Contexte

    Comme je le disais dans le premier post de ce nouveau blog, je suis devenu fan de la génération statique de sites et du langage Asciidoc. Mon choix s’était donc porté sur Jekyll pour lequel j’avais trouvé de nombreuses ressources.

    En particulier, Jekyll dispose de nombreux thèmes, mais presque aucun n’est nativement conçu pour permettre la rédaction en Asciidoc. Il faut donc se retrousser un peu les manches, et ajouter cette intégration soi-même. Ce n’est pas particulièrement difficile, mais quand on ne connait pas, cela nécessite d’aller piocher des informations à droite et à gauche…

    La base

    Le site du plugin a une documentation très bien fournie, qui donne la plupart des informations utiles pour commencer. Ce tutoriel est en grande partie une mise en application pratique de cette documentation.

    Les gems

    Il faut tout d’abord ajouter les gems nécessaires :

    On a ainsi un fichier Gemfile qui peut ressembler à ça :

    Fichier Gemfile
    source 'https://rubygems.org'
    
    gem 'jekyll', '~> 3.4.0'
    gem 'asciidoctor', '~> 1.5.5' (1)
    gem 'pygments.rb', '~> 1.1.1' (2)
    gem 'slim', '~> 3.0.7' (2)
    gem 'thread_safe', '~> 0.3.5' (2)
    
    group :jekyll_plugins do
      gem 'jekyll-asciidoc'
      gem 'jekyll-paginate' (3)
    end
    1 Facultatif (dépendance du plugin).
    2 Gems additionnelles nécessaires uniquement pour la coloration syntaxique et pour la surcharge de templates.
    3 Reprise des extensions déjà utilisées dans le thème de base dont on est partis…

    La configuration

    La configuration se place dans le fichier _config.yml, et permet de modifier le comportement par défaut de la génération Asciidoc. Par exemple :

    Extrait de configuration _config.yml sur Asciidoctor
    asciidoctor:
      # template_dir: _templates (1)
      base_dir: :docdir (2)
      attributes:
        # source-highlighter: pygments (1)
        # pygments-stylesheet: ! (1)
        imagesdir: /images (3)
        iconsdir: '{imagesdir}/icons' (3)
        stylesdir: /css (3)
        icons: font (4)
        icon-set: fa (4)
        experimental: 'true' (5)
        # numbered: 'true' (6)
        toc-title: Table des matières (7)
        toclevels: '4' (7)
    1 Spoiler des chapitres suivants…
    2 Les documents inclus (macro include) sont résolus relativement à partir du document (par défaut, il faut utiliser un chemin à partir de la racine du site, peu pratique quand on édite hors-ligne sans serveur Jekyll lancé).
    3 Chemins de base dans lesquels on trouve les images/icônes.
    4 Utilisation de la police Font-Awesome pour intégrer des icônes dans le texte (ce qui suppose d’avoir préalablement inclus la police associée dans le site).
    5 Activation des macros expérimentales d’Asciidoc, comme menu, btn ou kbd.
    6 Préfixe des titres/sous-titres par une numérotation de type "entreprise" (1.2.3.), pour ceux qui aiment…
    7 Paramétrage de la table des matières.
    Tous les paramètres doivent être des textes, sous peine de faire planter Jekyll, d’où les guillements autour des chiffres et des booléens.
    Il existe de nombreuses autres options de configuration que l’on peut paramétrer globalement pour le site à ce niveau. Je n’ai pas réussi à en trouver une référence exhaustive, mais si quelqu’un l’a… je suis preneur.

    Le style

    Le plugin jekyll-asciidoc va convertir les documents asciidoc en pages HTML, mais en utilisant des styles qui ne sont pas nécessairement ceux du thème de base…

    le but est d’avoir un rendu identique (ou le plus proche possible) entre un article écrit en Markdown et sa version Asciidoc.

    Pour atteindre ce but, plusieurs stratégies sont possibles :

    • Partir d’un thème CSS Asciidoctor, puis adapter celui-ci, afin de le rapprocher au maximum du thème Jekyll initial.

    • Étudier le code HTML généré par le plugin, et adapter le style du thème à ses spécificités.

    Pour ce blog, j’ai utilisé la première technique. Je suis parti du thème Asciidoctor par défaut, que j’ai finalement très peu modifié, mes compétences graphiques de développeur back full stack étant assez limitée.
    En cas d’intégration d’un thème Asciidoc (ou plus généralement d’un nouveau fichier CSS), il ne faut pas oublier de le référencer dans le template global du site pour qu’il soit importé (dans les _layouts ou dans les _includes).

    Premier post en Asciidoc

    À ce stade, on peut envisager d’écrire son premier article en Asciidoc, avec un rendu correct. On créé pour cela un fichier de test _drafts/hello-asciidoc.adoc ou _posts/2017-05-05-hello-asciidoc.adoc.

    Fichier de test
    = Hello Asciidoc!
    :author: Benoît Courtine
    :page-layout: post
    :page-description: Premier post utilisant Asciidoc
    :toc:
    
    == Chapitre
    
    Paragraphe.
    
    INFO: Vérification de l'affichage d'un bloc "Admonition" en langage Asciidoc.
    Lancement de Jekyll
    jekyll serve --drafts

    Pour aller (un peu) plus loin

    Coloration syntaxique

    Pour rédiger un blog technique, il est utile de disposer de la coloration syntaxique du code. Pour activer celle-ci, il faut :

    • Ajouter la gem pygments (voir ci-dessus).

    • Ajouter la configuration associée dans le fichier _config.yml (voir ci-dessus).

    • Ne pas oublier d’ajouter le fichier CSS des styles Pygments à l’entête HTML.

    Pour disposer d’un fichier CSS de base pour la coloration, il faut commenter la ligne de configuration pygments-stylesheet, puis lancer Jekyll. Un fichier sera créé dans le répertoire CSS configuré. On remet ensuite cette ligne dans la configuration, pour éviter que le fichier ne soit écrasé au prochain lancement. On peut alors modifier les couleurs, en s’inspirant des thèmes existants, disponibles par exemple ici.

    Réécriture de templates Asciidoc

    Cette étape est parfois nécessaire pour s’intégrer correctement dans un thème existant, surtout si celui-ci est basé sur Bootstrap. En effet, Bootstrap utilise principalement des div et des span. Or, le code HTML généré par Asciidoc utilise plus fréquemment des table (blocs d’admonition, etc.). Afin de simplifier le rendu HTML, nous allons réécrire les templates Asciidoc afin qu’ils génèrent des div.

    • Tout d’abord, on active la ligne de configuration template_dir dans le fichier _config.yml (cf. ci-dessus).

    • On ajoute au fichier Gemfile les gems slim et thread_safe (qui ne sont pas nécessaires si on n’a pas besoin de la surcharge des templates).

    La liste des templates que l’on peut surcharger est disponible dans le projet Asciidoctor Backends (répertoires html5). On peut utiliser indifféremment les syntaxes ERB, HAML ou SLIM.

    Personnellement, je préfère la syntaxe ERB, plus verbeuse mais plus facile à comprendre/écrire…

    Voici par exemple la réécriture du template "Admonition" dans une version Bootstrap.

    Fichier _templates/block_admonition.html.erb
    <%#encoding:UTF-8%><div<%= @id && %( id="#{@id}") %> class="<%= ['admonitionblock',(attr :name),role].compact * ' ' %>">
    
    <%
    adMap = {
      "note" => { "alertClass" => "info", "icon" => "info-circle", "text" => "Note:" },
      "tip" => { "alertClass" => "success", "icon" => "check-square-o", "text" => "Tip:" },
      "caution" => { "alertClass" => "warning", "icon" => "warning", "text" => "Caution:" },
      "warning" => { "alertClass" => "warning", "icon" => "warning", "text" => "Warning:" },
      "important" => { "alertClass" => "danger", "icon" => "exclamation-circle", "text" => "Important:" },
    }
    adMap.default = { "alertClass" => "info", "icon" => "info-circle", "text" => "Default:" }
    
    params = params = adMap[attr :name]
    %>
    <div class="alert alert-<%= params["alertClass"] %>" title="<%= @caption %>">
      <i class="fa fa-<%= params["icon"] %>"></i> <b><%= params["text"] %></b> <%= content %>
    </div>
    </div>

    Bonus : extension d’un bloc Asciidoc

    Reprenons le bloc ci-dessus. Il existe (au moins) deux manières différentes d’en faire le rendu en Asciidoc : avec la classe alert (cf. ci-dessus), ou avec la classe callout. Plutôt que de choisir, il est possible de permettre les deux rendus simultanément.

    On va pour cela qualifier le bloc :

    Syntaxe Asciidoc de qualification des blocs
    [INFO]
    Bloc info avec un rendu Bootstrap de type "alert".
    
    [INFO.callout]
    Bloc info avec un rendu Bootstrap de type "callout".

    Pour que cela fonctionne, il faut évidemment modifier le template ci-dessus, qui devient :

    Fichier _templates/block_admonition.html.erb
    <%#encoding:UTF-8%><div<%= @id && %( id="#{@id}") %> class="<%= ['admonitionblock',(attr :name),role].compact * ' ' %>">
    
    <%
    adMap = {
      "note" => { "alertClass" => "info", "calloutClass" => "info", "icon" => "info-circle", "text" => "Note:" },
      "tip" => { "alertClass" => "success", "calloutClass" => "success", "icon" => "check-square-o", "text" => "Tip:" },
      "caution" => { "alertClass" => "warning", "calloutClass" => "default", "icon" => "warning", "text" => "Caution:" },
      "warning" => { "alertClass" => "warning", "calloutClass" => "warning", "icon" => "warning", "text" => "Warning:" },
      "important" => { "alertClass" => "danger", "calloutClass" => "danger", "icon" => "exclamation-circle", "text" => "Important:" },
    }
    adMap.default = { "alertClass" => "info", "calloutClass" => "info", "icon" => "info-circle", "text" => "Default:" }
    
    params = params = adMap[attr :name]
    
    if role? 'callout'
    %>
    <div class="bs-callout bs-callout-<%= params["calloutClass"] %>" title="<%= @caption %>"><%= content %></div>
    <% else %>
    <div class="alert alert-<%= params["alertClass"] %>" title="<%= @caption %>">
      <i class="fa fa-<%= params["icon"] %>"></i> <b><%= params["text"] %></b> <%= content %>
    </div>
    <% end %>
    </div>
    Cette possibilité de surcharger des syntaxes Asciidoc s’applique à de nombreux types de blocs. Par ailleurs, en cas d’utilisation d’un backend différent (PDF par exemple), la qualification non supportée (callout) fera que le bloc sera rendu comme si la qualification n’existait pas.
    Il est également possible de créer de nouveaux blocs de toute pièce, mais cela suppose plus de travail (je n’ai jamais essayé jusqu’à maintenant), et ces blocs ne seront pas supportés en cas de changement de backend.

    Mise en pratique

    Au delà de ce blog, j’ai mis en place en entreprise des sites de documentation technique basés sur Jekyll/Asciidoc, pour remplacer sur certains domaines un serveur XWiki, inutilement complexe par rapport au besoin.

    Pour de la documentation, le thème Documentation est particulièrement indiqué. Mais comme expliqué en introduction, celui-ci ne supporte par défaut que le Markdown. En mettant en pratique les explications ci-dessus, on obtient le support Asciidoc.

    Pour ceux que cela intéresse, j’ai mis le support Asciidoc de ce thème en open-source sur la branche asciidoc, dans ce fork.

    Ce support est encore loin d’être complet, surtout du point de vue visuel (seuls deux templates Asciidoc ont été surchargés à ce jour). N’hésitez donc pas à contribuer.