Jekyll

Host a Website on GitHub with Jekyll – Part 2


Hi! I’m Dennis and I’ve been working at Linkbal as a software engineer since October 2017. In Part 1, we took a quick look at Jekyll and how to create and deploy a website to GitHub Pages. In this second and final part, let’s explore some of the customization features Jekyll provides us.

Layouts

In the previous example, you may have noticed the layout definition below in the front matter:

layout: post

While the markdown file provides the content of a page, the structure and appearance are defined in the layout file. We can create our own layout files, but because we are using an existing theme, we can customize the theme’s layout files instead.

First, let’s copy the layout files from the theme’s folder to our project (the specific folder to copy from will probably be different for you as it depends on the version of the packages installed).

cp -r vendor/bundle/ruby/2.3.0/gems/minima-2.5.0/_layouts .

If we take a look at the _layouts folder, we can see the 4 files below:

  • default.html
  • home.html
  • page.html
  • post.html

If we open the default.html file, we can see contents like the below:

<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">

  {%- include head.html -%}

  <body>

    {%- include header.html -%}

    <main class="page-content" aria-label="Content">
      <div class="wrapper">
        {{ content }}
      </div>
    </main>

    {%- include footer.html -%}

  </body>

</html>

It is an ordinary HTML file, but we can see a couple of the features provided by Jekyll and the Liquid template language it uses.

“Include” tags, like the below, allow us to include content from another file stored in the _includes folder:

{%- include header.html -%}

While the line below specifies where the content of a markdown file that uses the layout file will be injected:

{{ content }}

If we take a look at the contents of page.html:

---
layout: default
---
<article class="post">

  <header class="post-header">
    <h1 class="post-title">{{ page.title | escape }}</h1>
  </header>

  <div class="post-content">
    {{ content }}
  </div>

</article>

We can see that a layout itself can use another layout and that this layout can be used to display an article with a title in the top.

Now, we can also open the about.md file that ships with Jekyll. We can see in the front matter that this file uses the page layout.

---
layout: page
title: About
permalink: /about/
---

Also, the front matter defines a title and this title is injected in the line below in the page layout:

<h1 class="post-title">{{ page.title | escape }}</h1>

Now that we have an idea of how layouts work, let’s customize our website a little bit.

Includes

In the default.html layout file, we can see the line below:

{%- include header.html -%}

Because the default.html layout includes the header and all other layouts uses the default layout, it is obvious that all pages in our website includes the content in header.html.

Let’s take a look at the contents of the header.html file. Because it is also part of the minima theme, we need to copy this file as well:

mkdir _includes
cp vendor/bundle/ruby/2.3.0/gems/minima-2.5.0/_includes/header.html _includes

This include file is responsible for displaying the website header and shows many variables that Jekyll make available for us, as well as filters provided by the Liquid template language.

{%- assign default_paths = site.pages | map: "path" -%}

The line above, for example, shows the site.pages variable. It is an array of Jekyll’s Page variables (you can check the list of attributes a Page variable contains in Page Variables). Any .html or .md file in the root folder or a new subfolder that contains a front matter will be part of the site.pages variable. Then, we execute Liquid’s map filter on the site.pages to get an array of the paths of those pages.

{%- assign page_paths = site.header_pages | default: default_paths -%}

The next line creates a variable called page_paths. It is assigned the value in site.header_pages, but can also be assigned the value in default_paths in the case the former does not exist, what is possible with the use of Liquid’s default filter. We are going to come back to site.header_pages later.

{%- for path in page_paths -%}
  {%- assign my_page = site.pages | where: "path", path | first -%}
  {%- if my_page.title -%}
  <a class="page-link" href="{{ my_page.url | relative_url }}">{{ my_page.title | escape }}</a>
  {%- endif -%}
{%- endfor -%}

This last snippet iterates over the page_paths variable created before and creates a link in the header for each page that has a title (defined in the front matter).

To test what was just shown, let’s create a new page notes.md in the project’s root folder. Now, let’s add the content below to the new file:

---
layout: page
title: Notes
permalink: /notes/
---

If we refresh our website, we are going to see a new “Notes” link in the header. Add another page called contact.md to the root folder with the content below:

---
layout: page
title: Contact
permalink: /contact/
---

A new link is created as well. The problem is that the links are created in the alphabetical order, but we may want a different order to put the “Contact” page last, for example. In that case, we can use the site.header_pages mentioned before. This currently does not exist, but we can easily create this variable by adding the following lines to the _config.yml file:

header_pages:
  - about.md
  - notes.md
  - contact.md

You will notice the change will not be reflected immediately and will require the server to be restarted. After that, the header will look as expected.

The Resulting Header

The Resulting Header

Collections

Now, we are going to explore Collections that are a great way to group related content. Let’s use this feature to implement the “Notes” section in our website.

First, add the following content to _config.yml:

collections:
  - notes

Then, let’s create a _notes folder and add 2 files in it. The /_notes/note1.md:

---
menu_title: Note 1 Menu Item
title: Note 1 Title
---

Note 1 content

> A nice blockquote

A **formatted** line of *text*.

And the /_notes/note2.md:

---
menu_title: Note 2 Menu Item
title: Note 2 Title
---

Note 2 content

> A nice blockquote

A **formatted** line of *text*.

Now, let’s create a custom layout listing all our notes. It will be the /_layouts/note.html file and will contain the following content:

---
layout: default
---
<style>
.note {
  margin: 2rem 0;
  padding: 1rem 2rem;
}

.yellow {
  background-color: #fdf475;
}

.blue {
  background-color: #cbf0f8;
}

.note-date {
  font-size: 0.8rem;
  font-style: italic;
  color: gray;
}
</style>
<div class="notes-container">

  <header class="notes-header">
    <h1 class="notes-title">{{ page.title | escape }}</h1>
  </header>

  {%- for note in site.notes -%}
  <article class="note {{ note.background }}">

    <header class="note-header">
      <h2 class="note-title">{{ note.title | escape }}</h2>
      <p class="note-date">{{ note.date }}</p>
    </header>

    <div class="note-content">
      {{ note.content }}
    </div>

  </article>
  {%- endfor -%}
</div>

I added the styles directly in the layout, to keep things simple, as that is not the main focus of the article. As Jekyll has built-in support for Sass, please refer to the Docs to know how to manage your stylesheets.

You can see we were able to access our notes through the site.notes variable and even use a custom variable background we added to the front matter.

Restart the server and we can now access those notes in the /notes/ path.

The Notes Page

The Notes Page

The files we created in the _notes folder does not generate corresponding files in Jekyll’s build process. If you need, you can change this behavior as shown in Add content. This would generate files such as /_notes/note1.html in the build output. In our example, we could, for example, display only part of the content of the notes in the list and link each note to a page where the user can see their whole content.

Data Files

In this final section, we are going to take a quick look at Data Files. It allows us to create files with custom data to be used in our templates. Those can be YAML, JSON, or CSV files. Let’s do an example to illustrate its use.

First, create a file named /_data/contacts.yml:

- type: Email
  value: me@denakitan.com

- type: Phone
  value: (00) 0000-0000

- type: Website
  value: http://github.com/denakitan

This is enough to make our data accessible in our templates in the site.data.contacts variable. So, we can now edit our /contact.md file with the following content:

---
layout: page
title: Contact
permalink: /contact/
---

<table>
  {%- for contact in site.data.contacts %}
  <tr>
    <td>{{ contact.type }}</td>
    <td>{{ contact.value }}</td>
  </tr>
  {%- endfor %}
</table>

This will generate the below output:

The Contact Page

The Contact Page

As we could see, we can use Data Files to remove repetition in our pages by separating data and configuration. A practical use is illustrate in Navigation where it is used to create custom navigation for a website.

Conclusion

In these article, we could learn and practice basic Jekyll concepts such as Layouts, Collections and Data Files. There are plenty of content was not covered in the articles, so I highly recommend reading the documentation, as it is very well written and easy to understand.


Host a Website on GitHub with Jekyll – Part 1


Hi! I’m Dennis and I’ve been working at Linkbal as a software engineer since October 2017. In Part 1 of this article, I will introduce Jekyll and show how to create a new website and make it available publicly.

Jekyll

Jekyll is an open-source static site generator. Its GitHub repository README shows a very simple description: “Think of it like a file-based CMS, without all the complexity.” With Jekyll, we can create our website structure using HTML, CSS and Liquid Templates. After the structure is in place, we can focus on updating the website’s content, by just creating files using Markdown.

It is an intermediate solution that sits between static websites and web applications. We can add a little bit of dynamic behavior when generating the website but, in the end, it is served as a completely static website.

Jekyll is also the engine behind GitHub Pages, which can be used to host websites from GitHub repositories. Because we are not dealing with a database, updating a website is a matter of editing files and pushing the changes to GitHub,  This article is an introduction on how to work with Jekyll to create a website and how to host it on GitHub Pages.

Repository Creation

Our final goal is to have our website hosted on GitHub Pages. To achieve this, we need to upload our Jekyll project to a GitHub repository. We can have a exclusive repository for our website, but we can also store our project source in a folder of an existing repository. This last option is particularly useful for creating documentation websites for open-source software projects as it allows us to manage both the project and its documentation sources as a single project, making it easier to keep the later updated.

In this article, I am going to create a repository called ‘jekyll_website’ to be used exclusively to host the website by following the steps in the following link: https://help.github.com/en/articles/create-a-repo

Jekyll Installation

In this article, I won’t cover Jekyll’s installation process. It is very well documented in the Jekyll documentation and I assume you are going to follow that, but I will try to present some guidelines. I also assume you have a working Git installation.

Jekyll is distributed as a Ruby Gem and can be installed on most systems. It is recommended to work on a Unix-based system such as macOS or Linux, but you should not have problems working on Windows as well. By the way, this article was written on a Windows machine with Windows Subsystem for Linux enabled. You can take a look at the official documentation if you choose to go this path too.

Whatever system you choose to work on, the requirements are the same. You are going to need to have Ruby, RubyGems and build tools (GCC and Make) installed. If you, like me, are a Rails developer and already have a Ruby development environment installed, you should be good to go after installing Jekyll with the following commands (we are also installing bundler, a gem that helps us manage other Ruby gems in our project):

$ gem install jekyll bundler

New Project

Now, we are going to create a new Jekyll project:

$ jekyll new jekyll_website --skip-bundle

We passed the option --skip-bundle because we don’t want to install our dependencies system-wide. Instead, we want the installation of our dependencies to be limited to our project. But first, as we know we are going to host our website on GitHub, we want to setup up our project accordingly. First, open the Gemfile file created on your project’s root folder.

And remove the line declaring the dependency of the jekyll gem. It may differ depending on the version of the software you are working with, but in my case, I removed the following line:

gem "jekyll", "~> 3.6.2"

And uncomment the following line:

# gem "github-pages", group: :jekyll_plugins

Dependencies Installation

We can now install or dependencies locally with the following command:

$ cd jekyll_website

$ bundle install --path vendor/bundle

Local Server Startup

After that we can serve our website with the following command:

$ bundle exec jekyll serve

But, it’s highly recommended to use the command below instead:

$ bundle exec jekyll serve --livereload

This way the website will automatically build and reload each time changes are saved. This is particularly useful when we are writing articles and want to see how it is looking. You can stop the jekyll process at any time by pressing “Cmd (Ctrl) + C”.

Just open a browser and access the following address:

http://localhost:4000

Great! We already have a working website. You can see Jekyll comes with a pre-defined look & feel. Jekyll supports themes and it uses a theme called minima by default. You can check this fact by opening the Gemfile file, where there is a line setting the minima gem as a dependency:

gem "minima", "~> 2.0"

In this article, I will show you some examples on how we can start customizing our website. Although we can start our website from scratch, without a theme at all, it is probably easier to have a starting point, at least when using Jekyll for the first time.

But, before that, let’s add our website to GitHub to manage the changes in our website. You will see that, in the case of a Jekyll website, adding the project to GitHub not only means that we are controlling its versions, but also means that we are deploying our website for public access.

Deployment

To start the deployment process, let’s first enable GitHub Pages. To do so, access the settings of your repository and scroll to the GitHub Pages section. Let’s change the Source option from “None” to “master branch”. By doing that, GitHub will run Jekyll to build the website and serve it whenever we push changes to the master branch.

Now we can push our project to GitHub. But, before doing that, let’s edit our .gitignore file. The Jekyll project already comes with a .gitignore to prevent unnecessary files to be commited. But, as installing the gems locally is an optional step, it does not include entries to ignore the installed packages. So, let’s add the following lines to the .gitignore file:

.bundle
vendor

 

Now we can push our files to GitHub as usual:

$ git init
$ git add .
$ git commit -m "First commit"
$ git remote add origin git@github.com:denakitan/jekyll_website.git
$ git push -u origin master

 

You can now access your website at the URL provided by GitHub. In my case, it is: https://denakitan.github.io/jekyll_website/. If you still can’t see your website, it may take some time for GitHub to build it.

Creating a Post

Now that we have a website running, we can create our first blog post. To do so, add a new file to the _posts folder. I will name it “2019-02-28-my-first-post.markdown”.

The first thing we need to do then is to add the front matter section to this file. It is YAML block containing some metadata about our post. Let’s add the lines below to the file:

---
layout: post
title: "My First Post!"
date: 2019-02-28 08:26:44 +0900
categories: first post
---

After that, we just need to write our post using markdown syntax. Jekyll uses kramdown as its markdown converter. Let’s just add some content to test it:

A **formatted** line of *text*.

> A nice blockquote

## Code

{% highlight ruby %}
puts ‘Hello Jekyll!’
{% endhighlight %}

You should be able to see the new posted listed in the home page and access its content.

Conclusion

In this article we could see how to create a new Jekyll website and make it available for the public. In the part 2 of the series, I am going to show some examples on how we can use some of Jekyll’s features to customize our website structure.