Comment marche Jekyll ?
Source : How does Jekyll work? de Jack Phelan
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
oupage
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 62
after_markdown = convert(after_liquid) # line 66
place_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 :
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:
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:
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 :
{{ page.title | escape }}
{{ 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.
def process
reset # 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_stats
end
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.
def render
…
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
…
def render_docs(payload)
collections.each do |_, collection|
collection.docs.each do |document|
if regenerator.regenerate?(document)
document.output = Jekyll::Renderer.new(self, document, payload).run
document.trigger_hooks(:post_render)
end
end
end
end
…
def render_pages(payload)
pages.flatten.each do |page|
if regenerator.regenerate?(page)
page.output = Jekyll::Renderer.new(self, page, payload).run
page.trigger_hooks(:post_render)
end
end
end
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.
Génération des fichiers sans l’option brouillons
text.txt | frontmatter-not-post.md | 2016-05-05-post-without-frontmatter.md | yaml.yml | 2020-02-02-post-future.md | 2016-05-05-post-normal.md | |
---|---|---|---|---|---|---|
/ | copié | transformé | copié | copié | transformé | transformé |
/posts | omis | omis | post transformé | omis | omis | post transformé |
/drafts | omis | omis | omis | omis | omis | omis |
/data | omis | omis | omis | omis | omis | omis |
/my_output_collection | copié | transformé | copié | copié | omis | transformé |
/my_non_output_collection | copié | omis | copié | copié | omis | omis |
/underscore_dir | omis | omis | omis | omis | omis | omis |
/regular_dir | copié | transformé | copié | copié | transformé | transformé |
Génération des fichiers avec l’option brouillon
text.txt | frontmatter-not-post.md | 2016-05-05-post-without-frontmatter.md | yaml.yml | 2020-02-02-post-future.md | 2016-05-05-post-normal.md | |
---|---|---|---|---|---|---|
/ | copié | transformé | copié | copié | transformé | transformé |
/posts | omis | omis | post transformé | omis | omis | post transformé |
/drafts | Aucune | post transformé | post transformé | post transformé | omis | post transformé |
/data | omis | omis | omis | omis | omis | omis |
/my_output_collection | copié | transformé | copié | copié | omis | transformé |
/my_non_output_collection | copié | omis | copié | copié | omis | omis |
/underscore_dir | omis | omis | omis | omis | omis | omis |
/regular_dir | copié | transformé | copié | copié | transformé | transformé |
bash-4.3# tree .
.
├── 2016-05-05-post-normal.md
├── 2016-05-05-post-without-frontmatter.md
├── 2020-02-02-post-future.md
├── Gemfile
├── Gemfile.lock
├── _config.yml
├── _data
│ ├── 2016-05-05-post-normal-data.md
│ ├── 2016-05-05-post-without-frontmatter-data.md
│ ├── 2020-02-02-post-future-data.md
│ ├── frontmatter-not-post-data.md
│ ├── text-data.txt
│ └── yaml-data.yml
├── _drafts
│ ├── 2016-05-05-post-normal-drafts.md
│ ├── 2016-05-05-post-without-frontmatter-drafts.md
│ ├── 2020-02-02-post-future-drafts.md
│ ├── frontmatter-not-post-drafts.md
│ ├── text-drafts.txt
│ └── yaml-drafts.yml
├── _layouts
│ └── special.html
├── _my_non_output_collection
│ ├── 2016-05-05-post-normal-my_non_output_collection.md
│ ├── 2016-05-05-post-without-frontmatter-my_non_output_collection.md
│ ├── 2020-02-02-post-future-my_non_output_collection.md
│ ├── frontmatter-not-post-my_non_output_collection.md
│ ├── text-my_non_output_collection.txt
│ └── yaml-my_non_output_collection.yml
├── _my_output_collection
│ ├── 2016-05-05-post-normal-my_output_collection.md
│ ├── 2016-05-05-post-without-frontmatter-my_output_collection.md
│ ├── 2020-02-02-post-future-my_output_collection.md
│ ├── frontmatter-not-post-my_output_collection.md
│ ├── text-my_output_collection.txt
│ └── yaml-my_output_collection.yml
├── _posts
│ ├── 2016-05-05-post-normal-posts.md
│ ├── 2016-05-05-post-without-frontmatter-posts.md
│ ├── 2016-09-14-welcome-to-jekyll.markdown
│ ├── 2020-02-02-post-future-posts.md
│ ├── frontmatter-not-post-posts.md
│ ├── text-posts.txt
│ └── yaml-posts.yml
├── _underscore_dir
│ ├── 2016-05-05-post-normal-underscore_dir.md
│ ├── 2016-05-05-post-without-frontmatter-underscore_dir.md
│ ├── 2020-02-02-post-future-underscore_dir.md
│ ├── frontmatter-not-post-underscore_dir.md
│ ├── text-underscore_dir.txt
│ └── yaml-underscore_dir.yml
├── about.md
├── css
│ └── main.scss
├── feed.xml
├── frontmatter-not-post.md
├── index.html
├── regular_dir
│ ├── 2016-05-05-post-normal-regular_dir.md
│ ├── 2016-05-05-post-without-frontmatter-regular_dir.md
│ ├── 2020-02-02-post-future-regular_dir.md
│ ├── frontmatter-not-post-regular_dir.md
│ ├── text-regular_dir.txt
│ └── yaml-regular_dir.yml
├── text.txt
└── yaml.yml
9 directories, 57 files
bash-4.3# tree _site
_site
├── 2016
│ └── 05
│ └── 05
│ ├── post-normal-posts.html
│ └── post-without-frontmatter-posts.html
├── 2016-05-05-post-normal.html
├── 2016-05-05-post-without-frontmatter.md
├── 2020-02-02-post-future.html
├── Gemfile
├── Gemfile.lock
├── about
│ └── index.html
├── css
│ └── main.css
├── feed.xml
├── frontmatter-not-post.html
├── index.html
├── jekyll
│ └── update
│ └── 2016
│ └── 09
│ └── 14
│ └── welcome-to-jekyll.html
├── my_non_output_collection
│ ├── 2016-05-05-post-without-frontmatter-my_non_output_collection.md
│ ├── text-my_non_output_collection.txt
│ └── yaml-my_non_output_collection.yml
├── my_output_collection
│ ├── 2016-05-05-post-normal-my_output_collection.html
│ ├── 2016-05-05-post-without-frontmatter-my_output_collection.md
│ ├── frontmatter-not-post-my_output_collection.html
│ ├── text-my_output_collection.txt
│ └── yaml-my_output_collection.yml
├── regular_dir
│ ├── 2016-05-05-post-normal-regular_dir.html
│ ├── 2016-05-05-post-without-frontmatter-regular_dir.md
│ ├── 2020-02-02-post-future-regular_dir.html
│ ├── frontmatter-not-post-regular_dir.html
│ ├── text-regular_dir.txt
│ └── yaml-regular_dir.yml
├── text.txt
└── yaml.yml
13 directories, 29 files
bash-4.3# tree _site
_site
├── 2016
│ ├── 05
│ │ └── 05
│ │ ├── post-normal-drafts.html
│ │ ├── post-normal-posts.html
│ │ ├── post-without-frontmatter-drafts.html
│ │ └── post-without-frontmatter-posts.html
│ └── 09
│ └── 14
│ ├── frontmatter-not-post-drafts.html
│ ├── text-drafts.txt
│ └── yaml-drafts.yml
├── 2016-05-05-post-normal.html
├── 2016-05-05-post-without-frontmatter.md
├── 2020-02-02-post-future.html
├── Gemfile
├── Gemfile.lock
├── about
│ └── index.html
├── css
│ └── main.css
├── feed.xml
├── frontmatter-not-post.html
├── index.html
├── jekyll
│ └── update
│ └── 2016
│ └── 09
│ └── 14
│ └── welcome-to-jekyll.html
├── my_non_output_collection
│ ├── 2016-05-05-post-without-frontmatter-my_non_output_collection.md
│ ├── text-my_non_output_collection.txt
│ └── yaml-my_non_output_collection.yml
├── my_output_collection
│ ├── 2016-05-05-post-normal-my_output_collection.html
│ ├── 2016-05-05-post-without-frontmatter-my_output_collection.md
│ ├── frontmatter-not-post-my_output_collection.html
│ ├── text-my_output_collection.txt
│ └── yaml-my_output_collection.yml
├── regular_dir
│ ├── 2016-05-05-post-normal-regular_dir.html
│ ├── 2016-05-05-post-without-frontmatter-regular_dir.md
│ ├── 2020-02-02-post-future-regular_dir.html
│ ├── frontmatter-not-post-regular_dir.html
│ ├── text-regular_dir.txt
│ └── yaml-regular_dir.yml
├── text.txt
└── yaml.yml
15 directories, 34 files
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.1
3 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 :
7: require "mercenary"
8: require "pry-byebug"
9:
10: binding.pry
11:
=> 12: Jekyll::PluginManager.require_from_bundler
13:
14: Jekyll::Deprecator.process(ARGV)
15:
16: Mercenary.program(:jekyll) do |p|
17: p.version Jekyll::VERSION
Une fois les modifications effectuées, lors du lancement d’un build, le debug est désormais actif :
$ bundle exec jekyll build
[1] pry(main)>break ~/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/jekyll-3.3.1/lib/jekyll/site.rb:66
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.
Mercenary.program(:jekyll) do |p|
…
p.command(:build) do |c|
…
Jekyll::Commands::Build.process(options)
…
end
process_site
appelle ensuite site.process
.
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
. ↩︎