/ BLOG, JEKYLL, ASCIIDOCTOR, PLANTUML, CLOUDFLARE

My blogging stack and publishing process

I know a lot of people who have interesting things to say: when I can, I try to encourage them to write their own blogs. I think every developer who has interest should do it, with the minimal hurdle possible.

However, for reasons I cannot fathom, Medium has become the blogging platform of choice. Let’s face it, while the platform is okay-ish for non-technical posts, it’s not adapted for subjects that involve code - and formatting.

Besides that, Medium has a huge problem. If you use Medium, you basically surrender your own content to them.

In this post, I’d like to describe my blogging stack and publishing process, in order for everybody interested either to start one’s own blogging journey or migrate one’s existing stack and keep control over one’s content.

As of now, the following stack suits me quite well. Yet, it might not be a great fit for every context. Hence, I’ve included a section listing some alternatives of some bits and pieces that might be more adapted.

The foundation

The blogging platform is Jekyll, a static site generator: At its root, it reads Markdown files organized in a specific folder structure to generate HTML files that define the final blog content at build time. Compared to dynamic sites such as WordPress, it has the benefits of being fast - simple HTML, and secure - no PHP nor SQL injection.

But in some cases, e.g. simple boolean logic, or writing the publishing date, HTML files are not enough. To manage dynamic content, Jekyll integrates Liquid tags that allow simple logic.

Jekyll is built around a plugin architecture, to customize the platform. There are different types of plugin, depending on the kind of desired customization:

  • Generator: generate additional content
  • Converter: change a markup language into another format
  • Command: add subcommands to the jekyll executable
  • Tag: add additional Liquid tags
  • Filter: add custom Liquid filters
  • Hook: extend the build process

Plugins are written in Ruby. Plugins that need to be shared (or designed to be generic) can be installed as a Gem, while custom ones just need to be stored in a specific _scripts folder. For example, a plugin generates the sitemap.xml for the site.

To publish a new post, the process is the following:

  1. Create a new Markdown file in the dedicated _posts folder
  2. Add it to the Version Control System, and push it
  3. This should trigger the build that should include:
    • Generation of the HTML content
    • Deployment of said content on a web server to make it accessible to the world

The main issue regarding static sites is how to let readers provide feedback - comments. To cope with that, there are "Comments-as-a-Service" providers. Jekyll integrates Disqus natively, a widespread CaaS.

My specifics

From those foundations, I implemented the following customizations.

The Asciidoctor file format

I always found Markdown to be quite limited. When its limits are reached, one can always fallback to raw HTML, but then one tends to write a lot of HTML.

I found the Asciidoctor format a much better fit. Fortunately, there is a dedicated plugin to manage this format. With proper configuration, it becomes possible to write posts in Asciidoctor format.

PlantUML diagrams

UML is far less ubiquitous than most UML trainings claim. However, I still find it a quite useful way to communicate to stakeholders - or readers.

I found PlantUML some time ago: it allows to describe UML diagrams with simple text files in a custom syntax. There’s an online version available, as well as a Docker image. Regarding Jekyll, integration is provided by another plugin.

Theming

Jekyll is based on standard templates, with dedicated CSS classes. For that reason, Jekyll is able to provide themes based on those classes. Most themes are made available through Ruby gems. Changing a theme is just a matter of installing the gem and using it.

In my case, I re-designed the templates available in Jekyll. Hence, that made those theme gems useless…​ but I made my own style through a combination of custom and existing CSS.

For the record, Jekyll integrates with Sass out-of-the-box. This makes the process of creating one’s own stylesheets a bit less painful.

Version Control System

To start with Jekyll, one clones the GitHub repository, and customize it. To track changes, a VCS needs to be used. Because Jekyll is initially made available via Git, the logical follow-up is to continue to use it.

Jekyll is hosted on GitHub but I chose to use GitLab instead, because GitLab provides free unlimited private repositories. While my blog’s content is free for everyone to access, I prefer to keep the internal workings of the platform to myself.

Content generation

I’m using Jekyll for blog posts, but also to publish my past and future talks. I also want talks to be indexed and parsed by Google in a structured way. For that, it’s possible to use the schema.org microformat. It wouldn’t be feasible to copy-paste the same tags for every talk.

To automate the generation process, I created a generator plugin that reads YAML data to in order to create the page. Even though I don’t know Ruby, it’s quite straightforward to create a plugin using the available documentation and existing examples. Developing a plugin is a great way to customize one’s Jekyll instance.

Minification

Jekyll can easily be configured to provide minification : the generated HTML content can minified, including the JavaScript content if any. However, there’s a caveat to that: line breaks are kept, and yet, they make up a big part of the symbols that could be safely removed. The out-of-the-box minification feature goes only as far.

To remove every extra characters, a third-party plugin is available:

Jekyll HTML/XML/CSS/JS Minifier utilising yui-compressor, and htmlcompressor
— Jekyll minifier
https://github.com/digitalsparky/jekyll-minifier

It offers a lot of minification options, including the removal of line breaks, compression of JSON, etc.

Building

The jekyll command is used to generate the HTML content. As software developers, we should strive to automate as much as possible. Since my Jekyll source is hosted on GitLab, it’s only logical to use GitLab CI to build the site.

Thanks to GitLab, the build is integrated so that a commit to the master branch automatically triggers it.

Hosting

Once the site has been generated, it’s necessary to host the blog’s content. Fortunately, GitLab offers GitLab Pages, a static website hosting solution.

Again, thanks to GitLab, the build file can be configured with an additional publish step.

Here’s the configuration I use, to serve as a template:

variables:
  JEKYLL_ENV: production
  GIT_STRATEGY: fetch
  GIT_DEPTH: "3"

before_script:
  - cd /builds/nfrankel/nfrankel.gitlab.io

pages:
  stage: deploy
  script: bundle exec jekyll b -tV --config _config.yml,_config/_config_prod.yml -d public
  artifacts:
    expire_in: 1 day
    paths:
     - public
  only:
    - master

Miscellaneous customizations and improvements

Custom domain

By default, the website is served as a subdomain of gitlab.io i.e. http://<reponame>.gitlab.io. For "marketing" purposes, it’s better to use one’s own domain. GitLab Pages allows to serve the site under a domain you own e.g. https://blog.frankel.ch/. Just check the relevant documentation.

Cache

As mentioned above, static sites are much faster than their dynamic counterparts. However, GitLab Pages' performance can be improved by using a CDN. As CDNs go, Cloudflare can cache a whole lot of content on edge servers located all around the globe. This allows to store the content closer to each user, and to improve the response time by an amount depending on the distance between a user and the GitLab servers. Icing on the cake, Cloudflare’s free tier offering includes that feature.

Possible alternatives

As I mentioned above, what I describe works for me perfectly. Yet, there might be alternatives to consider. Those are only suggestions I’m aware of, this is by no way an exhaustive list.

Tech Alternatives Comment

Jekyll

Hugo

Based on Go

Flask

Based on Python

Asciidoctor

Markdown

As mentioned above, my preference goes to Asciidoctor as Markdown is much too limited IMHO

Git

What else?

GitLab

GitHub

I think GitHub has now a free option for private repos

BitBucket

If you’re already a user or are in love with Atlassian products

GitLab CI

Travis CI

Makes a lot of sense if you already are using GitHub

GitHub actions

Not battle-tested yet

GitLab Pages

GitHub Pages

Both seem to be equivalent based on my past experience

Cloudflare

Akamai

No free tier that I know of

Conclusion

If you want to start blogging, there’s no reason to use a platform that will get monetize your content, leaving you with nothing. Writing a blog post is a lot of work, the least you can expect in return is some sort of recognition from it. I hope this post will inspire you to start your own blog, or to migrate your existing one to a place where the content belongs to you.

Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
My blogging stack and publishing process
Share this