Si vous suivez ce blog, vous savez déjà que Jekyll est un
générateur de site statique développé en Ruby. Jack Phelan a décidé d’aller
jeter un œil dans le moteur de Jekyll histoire de mieux comprendre comment sont
traités les différents types de fichiers qui sont passés en entrée. Nous
traduisons
son article
afin de vous inciter à plonger un peu dans le code de Jekyll et prendre
connaissance des concepts fondamentaux de ce générateur. Nous espérons que cela
vous permettra de mieux appréhender la philosophie de Jekyll ou que cela vous
sera utile si vous songez à développer un plugin.
Jekyll peut paraître un peu déroutant au début. En effet
Jekyll ne fait pas grand-chose à vos fichiers, si ce n’est qu’il les classifie
de différentes façons.
Jekyll va soit copier, soit omettre, soit transformer les fichiers du répertoire
source dans le répertoire de destination1. Lorsque Jekyll transforme vos
fichiers, c’est toujours de cette manière, si ce n’est que la deuxième étape
peut être potentiellement sautée.2
Si un fichier commence par une entête
YAML Front Matter Jekyll va appliquer
les transformations suivante au fichier:
Interprétation du code Liquid : Le contenu du fichier est d’abord
parcouru par le parser de Liquid, les
variables comme site ou page auxquelles le modèle Liquid veut accéder
sont alors interprétées.
Conversion du contenu : en fonction de l’extension de fichier, Jekyll
fait appel à un convertisseur dédié, par example Kramdown pour les fichiers
.md ou .markdown, qui est chargé de convertir le résultat obtenu après
l’étape 1.
Parsing du modèle: Le résultat de cette conversion est alors transmis
dans la variable {{content}}, soit au modèle de page par défaut, soit à
celui qui est spécifié dans l’entête YAML Front Matter.
Le résultat de cette dernière conversion du modèle de page, généralement un
fichier HTML, est écrit dans votre répertoire de destination.
J’aimerais maintenant vous montrer un exemple où Jekyll applique cette
transformation. Ensuite, lors d’un
test complet de génération de site, nous
irons étudier la structure générale de l’algorithme au
cœur de Jekyll pour voir quels traitements sont effectués
sur les différents types de fichiers.
La transformation de Jekyll
Le mécanisme de transformation de Jekyll est situé dans
la méthode run du fichier renderer,
qui fait essentiellement la chose suivante, en sautant potentiellement quelques
étapes :
after_liquid=render_with_liquid(file_content)# line 62after_markdown=convert(after_liquid)# line 66place_in_layout(after_markdown)# line 71
Donc si nous transformons l’article présent dans le thème par défaut de Jekyll :
---
layout: post
title: "Bienvenue dans Jekyll !"
date: 2016-08-17 13:50:36 +0100
categories: jekyll update
---
You’ll find this post in your `_posts` directory. Go ahead and edit it and
re-build the site to see your changes. You can rebuild the site in many
different ways, but the most common way is to run `jekyll serve`, which launches
a web server and auto-regenerates your site when a file is updated.
To add new posts, simply add a file in the `_posts` directory that follows the
convention `YYYY-MM-DD-name-of-post.ext` and includes the necessary front
matter. Take a look at the source for this post to get an idea about how it
works.
Jekyll also offers powerful support for code snippets:
def print_hi(name)
puts "Hi, #{name}"
end
print_hi('Tom')
#=> prints 'Hi, Tom' to STDOUT.
Check out the [Jekyll docs][jekyll-docs] for more info on how to get the most
out of Jekyll. File all bugs/feature requests at [Jekyll’s GitHub
repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll
Talk][jekyll-talk].
[jekyll-docs]: https://jekyllrb.com/docs/home
[jekyll-gh]: https://github.com/jekyll/jekyll
[jekyll-talk]: https://talk.jekyllrb.com/
…vous pouvez voir le résultat des deux premières étapes de la transformation :
En entrée
1. Liquidifié
2. Converti
You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve`, which launches a web server and auto-regenerates your site when a file is updated.
To add new posts, simply add a file in the _posts directory that follows the
convention YYYY-MM-DD-name-of-post.ext and includes the necessary front
matter. Take a look at the source for this post to get an idea about how it
works.
Jekyll also offers powerful support for code snippets:
def print_hi(name)
puts "Hi, #{name}"
end
print_hi('Tom')
#=> prints 'Hi, Tom' to STDOUT.
Check out the Jekyll docs for more info on how to get the most
out of Jekyll. File all bugs/feature requests at Jekyll’s GitHub
repo. If you have questions, you can ask them on Jekyll
Talk.
You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve`, which launches a web server and auto-regenerates your site when a file is updated.
To add new posts, simply add a file in the _posts directory that follows the
convention YYYY-MM-DD-name-of-post.ext and includes the necessary front
matter. Take a look at the source for this post to get an idea about how it
works.
Jekyll also offers powerful support for code snippets:
defprint_hi(name)puts"Hi, \#{name}"endprint_hi('Tom')
#=> prints 'Hi, Tom' to STDOUT.
Check out the Jekyll docs for more info on how to get the most
out of Jekyll. File all bugs/feature requests at Jekyll’s GitHub
repo. If you have questions, you can ask them on Jekyll
Talk.
You’ll find this post in your _posts directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run jekyll serve, which launches a web server and auto-regenerates your site when a file is updated.
To add new posts, simply add a file in the _posts directory that follows the convention YYYY-MM-DD-name-of-post.ext and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works.
Jekyll also offers powerful support for code snippets:
defprint_hi(name)puts"Hi, \#{name}"endprint_hi('Tom')#=> prints 'Hi, Tom' to STDOUT.
Check out the Jekyll docs for more info on how to get the most out of Jekyll. File all bugs/feature requests at Jekyll’s GitHub repo. If you have questions, you can ask them on Jekyll Talk.
Puis vient la dernière étape où nous mettons tout cela dans la variable
{{content}} de notre modèle :
Modèle
3. Résultat final
{{ page.title | escape }}
{% if page.author %} • {{ page.author }}{% endif %}
{{ content }}
Welcome to Jekyll!
You’ll find this post in your _posts directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run jekyll serve, which launches a web server and auto-regenerates your site when a file is updated.
<p>To add new posts, simply add a file in the <code class="highlighter-rouge">_posts</code> directory that follows the convention <code class="highlighter-rouge">YYYY-MM-DD-name-of-post.ext</code> and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works.</p>
<p>Jekyll also offers powerful support for code snippets:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby">
<span class="k">def</span> <span class="nf">print_hi</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"Hi, </span><span class="si">\#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="n">print_hi</span><span class="p">(</span><span class="s1">'Tom'</span><span class="p">)</span>
<span class="c1">#=> prints 'Hi, Tom' to STDOUT.</span></code></pre>
</figure>
<p>Check out the <a href="https://jekyllrb.com/docs/home">Jekyll docs</a> for more info on how to get the most out of Jekyll. File all bugs/feature requests at <a href="https://github.com/jekyll/jekyll">Jekyll’s GitHub repo</a>. If you have questions, you can ask them on <a href="https://talk.jekyllrb.com/">Jekyll Talk</a>.</p>
Ceci est juste un exemple de conversion avec kramdown pour le markdown et
d’insertion du résultat dans un modèle. Jekyll intègre d’autres convertisseurs
comme
smartypants.
Jekyll inclut aussi par défaut un
convertisseur pour Sass dans
le
fichier de spécification de sa gem Ruby,
qui n’est pas un convertisseur intégré, mais vous comprendrez quand vous
lancerez la commande jekyll new. Vous pouvez installer d’autres convertisseurs
à l’aide de plugins. Les modèles sont des fichiers qui sont soit stockés dans
votre dossier _layouts, soit dans celui empaqueté dans la gem du thème utilisé
par votre fichier de configuration.
Le cœur de Jekyll
Maintenant que vous comprenez l’étape de transformation de Jekyll, regardons
comme elle s’intègre dans un processus de génération de site plus global à
partir de fichiers en entrée.
Si nous pitons le code exécuté lors de l’invocation de la commande
jekyll build, nous nous apercevons que
site.process
représente le cœur de Jekyll. Vous trouverez les parties importantes un peu plus
bas accompagnées de mes commentaires explicatifs. Reportez-vous à
la partie sur le debug si vous souhaitez vous baladez à votre tour
dans l’appel de la méthode.
# Public: Lit, processe et écrit le Site dans la destination.## Ne retourne rien.defprocessreset# vide tous les layouts/pages/static_file/data/collections du site.read# lit les fichiers de votre répértoire et les stocke dans un objet Site, les classer dépend# d’où ils se trouvent, ce qu'ils contiennent et de votre fichier de configuration.generate# Vous donne la chance de lancer des générateurs pour ajouter plus de choses au site..render# c'est la méthode chargée de la conversion.cleanup# se débarasse de tous les fichiers qui auraient pu restés d’une génération précédente ou qui traitent des metadonnées.write# écrit les fichiers dans votre dossier de destination.print_statsend
render applique la transformation de Jekyll aux fichiers qui possèdent une
entête YAML Front Matter. Les
documents sont créés à partir des fichiers de collection qui possèdent des
entêtes YAML Front Matter et les pages sont d’autres documents avec des entêtes
YAML. Vous devez déclarer les collections dans votre fichier _config.yml,
comme ça vous saurez que vous en avez. Vous devez également savoir que
les posts et les brouillons de posts sont simplement des collections spéciales,
ce sont donc aussi des documents.
defrender…render_docs(payload)# cette fonction s'occupe du rendu des fichiers de collections qui possèdent des entêtes Front Matter, y compris le dossier _posts (les brouillons sont ajoutés aux posts avec l’option --drafts)render_pages(payload)# cette fonction s'occupe du rendu des fichiers qui n'appartiennent pas à des collections mais qui ont des entêtes Front Matter# cela peut être vos fichiers `feed.xml`, `index.html`, `main.scss`, etc.…end…defrender_docs(payload)collections.eachdo|_,collection|collection.docs.eachdo|document|ifregenerator.regenerate?(document)document.output=Jekyll::Renderer.new(self,document,payload).rundocument.trigger_hooks(:post_render)endendendend…defrender_pages(payload)pages.flatten.eachdo|page|ifregenerator.regenerate?(page)page.output=Jekyll::Renderer.new(self,page,payload).runpage.trigger_hooks(:post_render)endendend
Test exhaustif d’une génération
Regardons à présent ce que nous obtenons lors d’un exemple de génération à
partir de quelques types de fichiers dans différents répertoires, avec et sans
l’option --drafts (active ou non la génération des brouillons). Le conteneur
Docker de ce test est dispos sur
bytesandwich/jekyll-outcomes.
Il recopie ces fichiers :
2016-05-05-post-normal.md# un post normal avec une date passée
2016-05-05-post-without-frontmatter.md# un post sans frontmatter, avec
une date passée
2020-02-02-post-future.md# un post standard, daté dans le futur
frontmatter-not-post.md# un fichier avec du frontmatter qui n’est pas un
post
text.txt# un fichier texte normal
yaml.yml# un fichier YAML normal
… dans chacun de ces répertoires :
/
/_posts
/_drafts
/_data
/_my_output_collection
/_my_non_output_collection
/_underscore_dir
/regular_dir
Sauf que pour chaque association de fichier et de répertoire, le nom du
répertoire de destination est ajouté à la fin du fichier de manière à ce que
nous puissions mieux appréhender les corresponsances entre les fichiers d’entrée
et les fichiers de sortie. Vous retrouvez un aperçu du résultat de la commande
tree après les deux tableaux.
J’ai fait un tableau avec une ligne par répertoire et une colonne par fichier,
la cellule contient l’opération effectuée sur le fichier, qui peut être :
copié sans altération
omis
transformé et placé dans le répertoire correspondant
post transformé, qui est ensuite placé dans une arborescence de dossiers,
crées d’après la date du post.
Les objets de Jekyll : Posts, Drafts, Pages, Data, Collections, Layouts et Includes
Le meilleur endroit pour continuer à apprendre est d’aller voir
la structure des répertoires de Jekyll,
où vous pourrez trouver des descriptions plus détaillées des types de fichiers
dans ces répertoires.
Déboguer Jekyll
Sous macOS, avec rbenv, en ligne de commande l’exécutable de Jekyll est un
script situé dans une Gem Ruby qui appelle
~/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/jekyll-3.3.13 où nous
pouvons commencer à débugguer à l’aide de pry-byebug si nous ajoutons deux
lignes (la 8 et la 10 dans l’extrait ci-dessous) :
Le fichier ~/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/jekyll-3.3.1
/exe/jekyll @ line 12 :
Jekyll embarque sa propre interface de ligne de commande, Mercenary, qui va
appeler la méthode build(site, options) dans build.process qui appelle à son
tour process_site, qui va charger la configuration par défaut et définir les
posts comme des collections, comme nous l’avons vu plus haut.
Voilà, maintenant vous en savez un peu plus sur les mécanismes internes de
Jekyll !
Lorsque Jekyll omet un fichier, il se peut qu’il lise le fichier comme une donnée à laquelle vous pouvez accéder à l’aide de variables Liquid dans d’autres fichiers de modèles Liquid. ↩︎
Il se peut très bien dans ce cas que vous ayez omis les entêtes YAML Front Matter. ↩︎
Pour savoir où se trouve l’exécutable de Jekyll, lancez la commande bundle show jekyll. ↩︎