Post thumbnail Jekyll

Published: 2019-07-30
Last updated: 2020-06-09 20:36

jekyll
ruby
blog
guide
meta

In this post I am going to test Jekyll! I will go through how to install it and some things I have learned on the way, such as how to use the Liquid preprocessor and how Jekyll structures its build output.

>Installing

If you are familiar with Ruby on rails, this should go smoothly. See the Jekyll page for the basic instructions. Since I was new, I just wanted to add the sidesteps I had to go from the instructions:

  1. Install a full Ruby development environment
    Apparently I already had this installed (Ubuntu 16):

     $ sudo apt install ruby ruby-dev
     [...]
     ruby is already the latest version (1:2.3.0+1).
     ruby-dev is already the latest version (1:2.3.0+1).
     $ ruby -v
     ruby 2.3.1p112 (2016-04-26) [x86_64-linux-gnu]
    
  2. Install Jekyll and bundler gems

     # I had not set up so gems could be installed globally, so I had to install it under my user
     $ gem install --user-install jekyll bundler
     # Then I had to add the Ruby gems to the path so I could execute them
     $ export PATH="$PATH:~/.gem/ruby/2.3.0/bin"
    
  3. Create a new site at ./myblog and go into the new directory

     # Here bundler would complain that it could not install all dependencies and failed (due to
     # lack of permissions). I therefore skipped the automatic install and made it install in my
     # user gems directory
     $ jekyll new myblog --skip-bundle
     $ cd myblog
     $ bundler install --path ~/.gem/ruby/2.3.0/gems
    
  4. Build the site and make it available on a local server at port 4000

     $ bundler exec jekyll serve --port 4000
    

Now you can start adding posts in by adding the to the _posts/ folder. As long as you run the serve option, Jekyll will keep updating the .html files everytime you change in the posts or assets (one exception, however, seems to be the _config.yml file). This is great when developing. It also has support for livereload so the web browser automatically refreshes when the site is changed.

$ bundle exec jekyll serve --port 4000
Configuration file: /home/emaus/blog/_config.yml
            Source: /home/emaus/blog
       Destination: /home/emaus/blog/_site
 Incremental build: disabled. Enable with --incremental
      Generating...
       Jekyll Feed: Generating feed for posts
                    done in 0.689 seconds.
 Auto-regeneration: enabled for '/home/emaus/blog'
    Server address: http://127.0.0.1:4000/
  Server running... press ctrl-c to stop.
      Regenerating: 1 file(s) changed at 2019-07-31 13:56:55
                    _posts/2019-07-30-first-post.md
       Jekyll Feed: Generating feed for posts
                    ...done in 0.313123519 seconds.

>Directory structure

Here is a snapshot of the directory structure after basically just setting up the page and adding a post as well as an asset.

$ tree
.
├── 404.html
├── about.md
├── assets
│   └── lorem.md
├── _config.yml
├── Gemfile
├── Gemfile.lock
├── index.md
├── _posts
│   ├── 2019-07-29-welcome-to-jekyll.markdown
│   └── 2019-07-30-first-post.md
└── _site
    ├── 404.html
    ├── about
    │   └── index.html
    ├── assets
    │   ├── lorem.md
    │   ├── main.css
    │   └── minima-social-icons.svg
    ├── feed.xml
    ├── index.html
    └── jekyll
        └── update
            └── 2019
                └── 07
                    ├── 29
                    │   └── welcome-to-jekyll.html
                    └── 30
                        └── first-post.html

11 directories, 18 files

So, some important things:

Output directory
The whole site is built into the _site folder. All of the files needed to serve incoming HTTP connections are placed here, i.e. CSS, HTML etc. This directory can be specified to another path by supplying an argument to the jekyll command.

Posts
Posts written in Markdown should be placed in the _posts directory and named as <year>-<month>-<day>-<name>.md. When built, they are placed in _site/jekyll/update/<year>/<month>/<date>/<name>.html.

Other Markdown pages
Other markdown pages are processed and placed in the root of the output directory, such as 404.html and index.html. However, the about.md page was treated diffrently since it had the attribute permalink: /about/ in its front matter (more about that below).

Assets
Assets are placed in a folder called assets. When the site is build these are copied into the _site/assets folder together with e.g. the .css-output from .sass-files. Here you can also place other types of files that you want to include in your posts, such as images.

>Post format

The posts are written in Markdown with a few additions:

  1. Front matter
  2. Liquid

>Front matter

The front matter is simply a header to the Markdown file with YAML format! It is both an indication that the file should be converted to an HTML file using the Liquid preprocessor, and a place where metadata can be defined for a post, such as the post’s title and definitions of Liquid page variables (accessed as memebers of the variable page).

---
# front matter tells Jekyll to process Liquid, defines page variables and other properties of the page
foo: a page variable
---

# My page

The variable foo has the value of 
<!--- i.e. a page variable -->

NB: You have to include this in your Markdown files, otherwise they won’t be converted to HTML.

>Liquid

Liquid is a form of scripting/templating engine similar to Jinja. It is statically built, but still versatile. It allows you to reduce repetitions (using objects, tags and filters), split source files (using includes), and apply formatting (templates). The version of Liquid that is build into Jekyll has some additions, but most of the time the official Liquid documentation can be used as reference.

>>Liquid objects

An object is really just a single unit that is processed by Liquid. It can contain for example strings, variables and filters. It is contained in double curly brackets:

{{ object }}

A string is just contained in quotation marks:

{{ "string" }}

Variables can be defined in either the front matter, by the Jekyll page builer, by plugins or in templates:

{{ page.date }}

>>Liquid tags

A tag can perform more advanced tasks, such as loops or inclusion of other files.

{% tag %}

A conditional:

{% if page.show_sidebar %}
  <div class="sidebar">
    sidebar content
  </div>
{% endif %}

We need to use the specific tags for inclusion and linking of resources, except for assets (and thus generated CSS):

<!--- Including CSS generated from SASS -->
<link rel="stylesheet" href="/assets/css/styles.css">

<!--- Links -->
[Link to an asset](/assets/<asset_name>)
[Link to a post  ]({% link _posts/<a_post_name> %})

Special include files can be used to reduce repetitions, and allowing to split files for better legibility and structure. The file to be included has to be placed in _includes/<filename>.

{% include <filename> %}

>>Example post conversion to Markdown

Let me just show an example of the Liquid preprocessing that is done:

---
layout:      post
title:       "Ay caramba"
date:        2019-07-30 11:14:00 +0200
categories:  jekyll update
tags:        ["test", "tutorial"]
foo:         bar
---

Published {{ page.date | date: '%B %d, %Y' }}.

{% for tag in page.tags %}
# Tag: {{ tag }}
{% if tag=="test" %}
TEST!
{% endif %}
{% endfor %}

```bash
$ exec dash
```

Other property: {{ page.foo }}

which is equivalient to the following Markdown document before conversion to HTML:


Published July 30, 2019.

# Tag: test
TEST!
# Tag: tutorial

```bash
$ exec dash
```

Other property: bar

>Concluding thoughts

I am quite amazed at how easy it was to set it up and install.

Jekyll is obviously very blog-centric. It is very easy to create posts with different layouts. It is very streamlined for setting up a single blog/article series, but can be modified to have several blogs on a single website.

Since the pages become static all you need is a simple web server that can serve HTTP connections with HTML pages. E.g. Apache, Nginx, NodeJS etc.

It is a bit annoying that you have to use the Liquid preprocessor to create intralinks (links between posts). They point to files that you created yourself with known exact locations before preprocessing, I think it would have been nice if this was handled automatically instead. Sure, they are preprocessed and converted from Markdown to HTML, but why can’t they instead keep the same directory structure? Perhaps this can be avoided somehow.

The amount of plugins seems to be fairly limited. Here is a list I found that seems to point out some good ones. Pages can still be dynamic just by adding the appropriate Javascript to it. For example using dynamic pages with AJAX would make it possible to remove the pagination from the main page and instead load the posts dynamically. The list of posts could perhaps be passed to Javascript by using some Liquid preprocessing that creates a Javascript variable. Here is an example of how to add search functionality to your Jekyll blog.

The framework in itself is really not limiting compared to writing raw HTML pages, it just makes it a lot simpler to write and manage. With templating you get similar features as when creating pages dynamically with PHP, Python and NodeJS. You however miss the possibility of dynamically creating pages (such as reading from databases) without using client side AJAX. This will make it a bit more cumbersome to create shops and other pages where you need to do server-side verification.