I haven't blogged regulary ever in my life so I decided now it's time for change and blog frequently about technology. This blog was using ghost cms deployed on docker to do it and I decided it would be nicer to have static pages that I can commit using git and deploy directly to webserver without any middleware.
At first I thought it would be fun to build such thing from scratch but then I remember how complicated life become in terms of making blog. For complete working solution you need to add rss / seo / social media metadata / site map to name a few. And most painfull, you need to maintain it.
I got myself reminded about a great tool for generating web pages from markdown jekyll, after quick reading about features it turned out it have all of above and more so I decided to go for it.
At first I needed to install ruby on OSX Mojave
brew install rbenv ruby-build
echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile
source ~/.bash_profile
# Install Ruby
rbenv install 2.6.3
rbenv global 2.6.3
ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]
Then I can proceed with jekyll and migration of ghost blog
gem install bundler jekyll
jekyll new vane.pl
cd vane.pl
#migrate
gem install jekyll-import
ruby -r rubygems -e 'require "jekyll-import";
JekyllImport::Importers::Ghost.run({
"dbfile" => "ghost.db"
})'
After migration two directories will appear _drafts and _posts and all pages will be in main directory.
Unfortunately dates were not migrated properly so my posts directory looked something like that
15:54 1970-01-18-why-serverless-is-a-next-big-deal.markdown
15:54 1970-01-19-understand-how-to-theme-material-ui.markdown
15:54 1970-01-19-world-of-machines.markdown
15:51 2019-06-25-welcome-to-jekyll.markdown
So I needed to migrate those dates manually and also change date inside those files. I also wanted to get tags because those were also not migrated so I created custom sql script that gets all the tags, slug, title and formatted date so I can migrate those posts.
select
p.id, p.title, p.slug, group_concat(t.name), strftime('%Y-%m-%d %H:%M:%S',datetime(p.published_at)) as published
from posts as p
inner join posts_tags as pt on pt.post_id = p.id
inner join tags as t on t.id = pt.tag_id
group by p.id
order by p.published_at desc
I exported results as csv file and I could build a script that will merge csv file with those files created by jekyll migration script.
After hour later it was done using this a little ugly python script that is looking for file matching slug in _posts directory and replacing it's date with correct one adding tags and finally saving it as file with proper date in front. You can download it from this location
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import csv
import os
class Constraints:
CSV_FILE = 'blog_tags.csv'
POSTS_DIR = '_posts'
TIMEZONE = '+02:00'
def write_post(date, tags, date2):
with open('{}/{}'.format(Constraints.POSTS_DIR, p)) as post:
post_array = post.readlines()
new_date = 'date: {}.000000000 {}\n'.format(date, Constraints.TIMEZONE)
for i, line in enumerate(post_array[:]):
if line.startswith('date:'):
post_array[i] = new_date
post_array.insert(i, 'tags : {}\n'.format(tags))
break
# write new file
new_fname = '{}/{}-{}'.format(Constraints.POSTS_DIR, date2, p[idx:])
with open(new_fname, 'w+') as newpost:
newpost.writelines(post_array)
if __name__ == '__main__':
posts = os.listdir('_posts')
with open(Constraints.CSV_FILE) as f:
data = csv.DictReader(f)
for p in posts:
f.seek(0)
for row in data:
idx = p.find(row.get('slug'))
# we found file named as slug so we can process it
if idx > 0:
date = row.get('published')
tags = row.get('tag_names').split(',')
date2 = date.split(' ')[0]
# read, replace and write post file
write_post(date, tags, date2)
After I removed old posts and run jekyll
rm -rf _posts/1970-01-1*
bundle exec jekyll serve
I was able to see results under http://127.0.0.1:4000
I wanted to see my blog posts without /date/slug format so I modified _config.yml by adding this line:
permalink: :title/
Also I needed to copy assets from ghost to assets directory inside jekyll project.
Later I also added lines to comprese sass files, seo plugin and syntax highlighting.
highlighter: rouge
sass:
style: compressed
plugins:
- jekyll-feed
- jekyll-sitemap
- jekyll-seo-tag
There is a great post from Arthur Gareginyan about syntax highlighting configuration. Basically you need the css file with highlighting style and knowledge how to color things.
It was easy so I decided to make my own skin. I wanted to make it dark so I started reading documentation, study blank_template from repository and default theme.
So here is my basic description how it works.
First we create assets/css/main.scss directory with
@import "main";
and _sass directory with main.scss file where we include our css with syntax, mine is native. Also we add all style configuration. I used Better motherfucking website as a base to keep my page smooth.
Then you need to create _layouts directory and put files in there. File names are corresponding to names in markdown files with variable layout
---
layout: post
---
The default template name is located in main project directory in file index.md mine was named default so I created _layouts/default.html
There at least two scopes of variables site and page. You can get for example title by typing {% raw %}
And acces some feed and seo plugins by adding variables in head {% raw %} {%- feed_meta -%} {% endraw %}
To list all posts you can write: {% raw %} {% for post in site.posts %} {{ post.title }} {{post.date | date: "%Y-%m-%d %H:%M:%S"}} {{post.content | truncatewords: 35}} {% endfor %} {% endraw %} There are many filters available in jekyll trough Liquid template language so you can build tempaltes fast.
You can even add pagination but I skipped it for now.
To format posts you need to create _layouts/post.html.
There you can ex. list all tags inside posts and use it as keywords in meta like this:
{% raw %}
{% endraw %}
After a few hours of expreriments I had dark mode blog with all I needed and I could test it on my devices.
To serve jekyll with drafts on my local machine I can use. Then I can test if everything is working looking fine on my phone.
bundle exec jekyll serve --drafts --host 0.0.0.0
To compile build you should add your domain name and base name into _config.yml mine is looking like that :
baseurl: "" # the subpath of your site, e.g. /blog
url: "https://vane.pl"
and then compile it using this command
jekyll build
Results are in _site directory and you can copy them wherever you want on some cloud server or even configure github pages and serve your site directly from github.
Have fun.