Hello World
It seems that every 10 years I feel compelled to renovate the way I blog. I've just installed new blog system on my Mac. It uses Mkdocs, or more precisely its variant Material for MkDocs1, an open source SSG and is published on Gitlab Pages. I have used it as the documentation system in my previous organisation and I liked it lot, and I recently realised it is good for blogging systems too.
First step: install the blog system
Warning
Note that pipx creates a venv at ~/.local/pipx/venvs/mkdocs-material
Install additional plugins
mkdocs-material comes with a lot of plugin already, but you may want to install others. In which case you need to install the python package and then enable it in the Mkdocs configuration file.
and in mkdocs.yml, add:
Failure
If you don't activate the venv for the mkdocs-material package or activate a different one, mkdocs build process will complain that the plugin is not installed
Tip
It's probably a good idea to freeze all of the python dependencies into a requirements.txt file to make it easier to install and upgrade:
python -m pip freeze > requirements.txt
Create a new project
This will create a docs directory and a index.md file inside it, and a mkdocs.yml alongside it.
The index file double as rudimentary "Getting started" doc, so it's worth opening and reading it.
Configuration
All the configuration for mkdocs goes into the file mkdocs.yml at the root of the project.
It has several sections, to configure the website's metadata, and the plugins2 that are going to be used.
A typical configuraiton for blog only project looks like this:
site_name: rmy blog
site_description: Musings on things
site_dir: public
site_url: https://blog.example.com
plugins:
- blog:
blog_dir: .
- social
- tags
- search
- meta
- rss
theme:
name: material
features:
- navigation.indexes
Note
in the plugins section, all listed but the last one are included in the mkdocs-material python package, so they don't need separate installation. However they may have prerequisite, hence the [imaging] passed to the forementioned package in the first section.
Warning
Of all the plugins, blog is the only one required for a blogging system. Mkdocs is primarily a technical documentation system, so blogging is not core functionality.
Tip
like what we did for the first plugin blog, all the plugins can take additional parameters. You can see the default plugins list and their configuration on the Material for Mkdocs documentation.
Build the public site
This process will create an output directory (by default site, unless it has been overriden by site_dir configuration directive) in which the directory structure in docs is recreated and all the Markdown files and their metadata are proccessed and rendered as a static html website.
Warning
if the configuration file, mkdocs.yml doesn't exist or is missing directives, there will be error shown in the log and the site won't be created.
Serve the website locally
Note
mkdocs serve monitors file system change and will reload the local site whenever a file has been modified. Errors will be shown in the log.
Success
if the site building succeed, the local website (for preview only, it's not production grade) is availble at http://127.0.0.1:8000/
RSS feed
The RSS feeds will be created in multiple format (XML Atom and Json) and there will be separate feed for created entries and updated entries.
Metadata: Categories, tags and draft
Like most Markdown-based SSG that I know of, Mkdocs supports embedding metadata about an article in the Markdown document itself, at the top
and enclosed beweenm two lines made of ---. That header section is call "Front matter", and that's where you can define the title, creation date, as well as listing the authors involved and the tags associated with it. That's where one can indicate whether a document is a draft. Of them all, only title: and date: are mandatory.
Example
Authors
In the example above, you may be wondering where does janedoe came from.
Authors are defined in a docs/.authors.yml file and it look like this:
authors:
janedoe:
name: Jane Doe # Author name
description: Conservationist # Author description
avatar: https://test.com/jane.jpg # Author avatar
# slug: url # Author profile slug
# url: url # Author website URL
The properties that are commented out are the optional ones.
Meta plugin and project structure
One of the builtin plugin is called meta and it allows defining a file (by default .meta.yml) that you put inside a directory.
Then, any markdown you drop inside that directory will inehrit the metadata held in the meta file (and merged with the document's own metadata), saving you from the hassle of adding repeatedly the same front matter directives in multiple Markdown files.
That way you can for example create a directory for each category and the .meta.yml file in each will have the front matter directive to describe that category, so you don't have to do it in the Markdown document that you just drop in the appropriate category directory.
You can use the same technique to create a Draft directory with a .meta.yml file containing only draft: true.
Any draft you want to create goes into that directory. When a document is ready to publish you move it out of the Draft directory.
Here's how it looks for me in my initial setup:
── docs/
│ ├── .authors.yml
│ ├── index.md
│ ├── posts/
│ │ ├── CheatSheets/
│ │ │ └── .meta.yml
│ │ ├── DeliberatePractices/
│ │ │ └── .meta.yml
│ │ ├── Drafts/
│ │ │ ├── .meta.yml
│ │ │ ├── git-workflow.md
│ │ │ └── post-as-draft.md
│ │ ├── InterestingLinks/
│ │ │ └── .meta.yml
│ │ ├── LongArticles/
│ │ │ └── .meta.yml
│ │ ├── Ramblings/
│ │ │ └── .meta.yml
│ │ └── Tutorials/
│ │ ├── .meta.yml
│ │ └── first-post.md
│ └── tags.md
├── mkdocs.yml
├── public
Note
mkdocs's blog plugin expects the existence of docs/posts diretory, and any document inside it (directly or inside sub-directories) will be managed by it (will have it slug, archive generated, and front matter metadata processed, etc).
Directory and document created outside posts will stil be processed by mkdocs as a regular documentation document, not as blog posts. Ideal for ancilliary pages like Contact, About, etc.
Deploy the website
This is the part that's different for everyone. Mkdocs blog's static website output is ideally suited for the static page hosting offering from major managed git providers, especially that mkdocs was built as a technical documentation system. In particuliar if you use Github or Gitlab, the process is easy. For Gitlab, you create a project and then follow the wizard in "Deploy > Page" from the sidebar.
For reference, here's how my .gitlab-ci.yml looks like:
# The Docker image that will be used to build your app
image: python:latest
create-pages:
stage: deploy
pages:
# The folder that contains the files to be exposed at the Page URL
publish: public
rules:
# This ensures that only pushes to the default branch will trigger
# a pages deploy
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
# Functions that should be executed before the build script is run
before_script:
- pip install "mkdocs-material[imaging]"
- pip install mkdocs-rss-plugin
script:
- mkdocs build
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- ~/.cache/
artifacts:
paths:
- public