Introduction
Since Octopress has now been deprecated for pure use of Jekyll, this blog has now been switched to use exactly that. See this post as a walkthrough on creating a functional blog via Jekyll (part 1). This is yet another collation of snippets I have found useful, to be used as a reference for my future self - and maybe others.
Starting off
You can find the installation instructions for Jekyll in the official documentation.
After the Jekyll gem has been installed scaffolding a new site is as easy as
jekyll new blog_name
This will create a new folder with a starter site. To serve your site to preview it, run the
jekyll --serve
command and navigate to http://localhost:4000 (the default port) with your favourite browser.
Defaults, excerpts and URL structures
By default the home page will display the full list of posts with all it’s glorious content. This might be a bit too much for longer posts. In order to enable excerpts with links to the full post you need to configure the excerpt_seperator. This can be specified in the front matter of each post. We can also specify the format of the permalink to the posts, with a sane URL structure including the date and title of the post.
Instead of repeating ourselves in the frontmatter of each post we can DRY it up a bit by specifying defaults in the config.yml file:
defaults:
-
scope:
path: "" # an empty string here means all files in the project
type: "posts" # previously `post` in Jekyll 2.2.
values:
layout: "post"
excerpt_separator: "<!`--` more `--`>"
comments: true
permalink: "/blog/:year/:month/:day/:title"
The format YYmmDD is obviously locale specific - but one advantage with using this format is that your posts can be chronologically ordered even on the file system. The final URL for a post would look something like this:
http://riaanhanekom.com/2018/01/21/travis-with-sonarcloud
With the configuration above applied content will only be shown on the home page up to where the content processor finds the <!--more -->
marker:
Override the look and feel
We can create a main stylesheet in the assets directory in your source folder. main.scss will be the Sass file included after everything else so you can override any styles that you want. Since we’ve used the minima theme it’s important that we import it at the top. Let’s put in a separator between the posts:
@import "minima";
.post-list>li {
border-bottom: 1px solid #b6b6b6;
padding-bottom: 30px;
margin: 10px 0px 30px 0px;
}
I’m not a big fan of the 800px fixed-width style - by adding the following CSS into assets/main.scss we can take up more real-estate on the screen:
.wrapper {
max-width: none;
margin-right: auto;
margin-left: auto;
padding-right: 10%;
padding-left: 10%;
}
In order to override the markup provided by the default theme you can “eject”, copy the files from the gem installation directory into your own source directory and modify them at will.
The command
bundle show minima
will show you the source directory to copy the files from.
Productionise it!
As with any software development it’s important to get the production aspects out of the way. This can always be modified later on, but doing this very early in the process will eliminate a bunch of “whoops, didn’t think about that” moments. Deploying to GitHub pages is a popular method of serving a blog made with Jekyll, but since I’ll be deploying this on a private server we’ll focus on building and running a docker container for this purpose. Let’s create a simple NGINX server to host our application with this Dockerfile:
FROM nginx
COPY ./_site /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
COPY default.conf /etc/nginx/conf.d/default.conf
Simple enough. Jekyll generates the site static content under the _site directory which can we can copy into the default serving directory of NGINX. I’ve added a configuration file to add cache control headers for static content (images, js, css). HTML pages are still set for the browser to check back to server if any content has changed. We also enable gzip and set up NGINX to scan for the index.html file in directories to have nice file-less URLs:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
server {
location / {
try_files $uri $uri/index.html $uri.html =404;
}
location /assets {
expires 1M;
add_header Cache-Control "public, max-age=691200, s-maxage=691200";
}
location /images {
expires 1M;
add_header Cache-Control "public, max-age=691200, s-maxage=691200";
}
rewrite ^/(.*)/$ /$1 permanent;
expires $expires;
}
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
gzip on;
include /etc/nginx/conf.d/*.conf;
}
At this point in time don’t forget to update the header include template to add a cache buster for the stylesheet:
<link rel="stylesheet" href="{{ "/assets/main.css" | relative_url }}?{{site.time | date: '%s%N'}}">
The generated link to the stylesheet would look something like /assets/main.css?1519308247603964426. Simply, the time value at the point of generation would be appended to the stylesheet URL allowing us to effectively cache the asset forever on clients until it changes.
Working with drafts
In order to work on draft posts and not have them published, you need to create a ‘drafts’ in your source folder as per the documentation. When running jekyll serve , pass in the –draft parameter to show drafts. Depending on your needs it might also be useful to add the –future parameter in order to display posts that have a date in the future.
Paging
No good blog should be without paging. By default my installation came with the jekyll-paginate gem installed. I’ve found that the next iteration of the gem, jekyll-paginate-v2 works better and is simpler to implement.
In order to activate, add the jekyll-paginate-v2 to the plugins section of the config and your Gemfile. There are tons of configuration options for pagination, but here were the ones I found important for now:
pagination:
enabled: true
collection: 'posts'
per_page: 8
permalink: '/page/:num/'
Where your posts are displayed you will need to iterate over the paginator.posts instead of posts:
for post in paginator.posts
If you are using the minima theme, it’s time to copy over the home.html file from the layouts folder and modify it. We also shouldn’t forget to add the pagination links at the bottom:
{% if paginator.total_pages > 1 %}
<ul>
{% if paginator.previous_page %}
<li>
<a href="{{ paginator.previous_page_path | prepend: site.baseurl }}">Newer</a>
</li>
{% endif %}
{% if paginator.next_page %}
<li>
<a href="{{ paginator.next_page_path | prepend: site.baseurl }}">Older</a>
</li>
{% endif %}
</ul>
{% endif %}
This gives us an easy way to navigate between pages:
Hmmm, functional, but not pretty. We’ll improve on this in future posts.
Photo by rawpixel.com on Unsplash