Fastest way to set up and manage an Mkdocs Material project
09 Mar 2024If I wouldn’t be able to control myself, I would create a new website every week. Creating a website about … any topic really, helps me structure the knowledge I have or am in the process of collecting about it. The tools to create a new website have changed through the years. There was my Blogger period, my WordPress period, my Jekyll period. And now I am in my Mkdocs period.
Not the vanilla mkdocs, mind you. I am using the Material for MkDocs theme. It’s a beautiful theme, with a lot of plugins and extensions, and it’s very easy to use. It felt like an upgrade from Jekyll: auto-reload upon edit, very fast and it just works. The times I’ve struggled to get ‘jekyll serve
’ or ‘bundle exec jekyll serve
’ running …
The process of setting up a new Mkdocs project was still too slow and cumbersome. So I decided to make a bash script to make things easier and faster: introducing pforret/mkdox.
1. create new bashew script
I start by creating a new script with bashew script
. To make things very portable (I don’t want to worry about which version of Python is installed on my system), I started looking into using a Docker-based approach. Luckily there was already a basic Docker image for Mkdocs available on Docker Hub. I used this as a basis and I added more default plugins and settings to it.
This means I require Docker to be installed and running on my system. I added a check for this at the start of my script:
docker -v &>/dev/null || IO:die "Docker is not installed or not yet started"
docker ps &>/dev/null || IO:die "Docker is not yet started"
I added some plugins to the Docker image with
pip install --no-cache-dir \
weasyprint \
mkdocs-material[recommended] \
mkdocs-material[imaging] \
mkdocs-awesome-pages-plugin \
mkdocs-with-pdf \
markdown-include ;
2. add basic commands
mkdox new
- Purpose: create a new website with all the plugins and settings I need
- The actual creation of the mkdocs site is done by the mkdocs Docker image. I created a template website I always copy, with a
mkdocs.yml
file that contains all the settings I need for a new website. This is copied automatically to the new project folder. Setup of a new site: less than 2 seconds.
⏳ Create new Mkdocs Material project in example
Run 'mkdocs new' via Docker
INFO - Writing config file: example/mkdocs.yml
INFO - Writing initial docs: example/docs/index.md
Create mkdocs.yml ...
Create docs/about/extensions.md ...
Create docs/about/index.post ...
Create docs/about/plugins.md ...
Create docs/about/index.pre ...
Create docs/news/posts/2024-02-post2.md ...
Create docs/news/posts/2024-01-post1.md ...
Create docs/news/index.md ...
Create docs/index.md ...
Create .gitignore ...
✅ New Mkdocs Material project created in 'example'
# took 2s to create
mkdox serve
- so now you just go into that folder that you just created above and run
mkdox serve
and you have a local server running with auto-reload. This also automatically starts your browser with the right URL.
WARNING - Config value 'dev_addr': The use of the IP address '0.0.0.0' suggests a production environment or the use of a proxy to connect to the MkDocs server. However, the MkDocs' server is intended for local development purposes only. Please use a third party production-ready server instead.
INFO - Building documentation...
WARNING - without generate PDF(set environment variable ENABLE_PDF_EXPORT to 1 to enable)
INFO - Cleaning site directory
INFO - Documentation built in 0.39 seconds
INFO - [15:56:01] Watching paths for changes: 'docs', 'mkdocs.yml'
INFO - [15:56:01] Serving on http://0.0.0.0:8000/
Open http://localhost:8000 in browser (macOS)
INFO - [15:56:08] Browser connected: http://localhost:8000/
This is what that looks like:
mkdox build
The purpose of a website is that it becomes available online at some point. So I added a mkdox build
command that builds the website to a site
folder, and then checks this in. This is the folder you can then serve from your web server.
# in the beginning this was just
mkdocs build
git add docs site
git commit -m "$MESSAGE"
git push
But this became a much more intelligent command later on.
3. add more features
mkdox post
I use the blog plugin for Mkdocs Material, so I created a fast way to create a new blog post.
❯ mkdox post
Post date (2024-03-09) >
Post title (New post) > My new blog on waffles
Post categories (blog,post) > news,waffles
✅ New post created: docs/news/posts/2024-03-09-my-new-blog-.md
mkdox toc
and index.pre
/index.post
I often thought it would be handy to have index.md
files that were automatically built with the links to the subpages. So I developed a system to do this.
- I can do
mkdox toc
to manually generate a table of contents for a folder - I can do
mkdox recent
to manually generate a list of the most recent pages - I can add
index.pre
andindex.post
files to a folder, and these will be prepended and appended to theindex.md
file, which will be generated automatically as a table-of-contents when I runmkdox build -I
. - this led to more development of the
mkdox build
command: create index.md files, create PDf version, create site, commit and push site.
Configuration
So I can now start up a new website in seconds. Creating a GitHub/BitBucket repo to store it, setting up new a Forge website that automatically publishes after a git push
: maybe another 5 minutes.
Then there’s still the mkdocs.yml
file that I need to adjust for each new project. That’s something I do in a text editor.
site_name: "{SITE_NAME}"
site_description: "{SITE_NAME} by {USERNAME}"
theme:
name: material
palette:
primary: red
font:
text: Nunito
copyright: "© {CREATION_YEAR} {SITE_NAME} • {USERNAME}"
Usage
Version : v0.4.0 (Mar 9 13:17:55 2024)
Purpose : easy wrapper for Material Mkdocs in Docker mode
Usage : mkdox [-h] [-q] [-v] [-f] [-G] [-I] [-Q] [-R] [-T] [-X] [-l <log_dir>] [-t <tmp_dir>] [-D <DOCKER>] [-E <TITLE>] [-H <HISTORY>] [-L <LENGTH>] [-P <PORT>] [-S <SECS>] <action> <input?> <output?>
Flags, options and parameters:
-h|--help : [flag] show usage [default: off]
-q|--quiet : [flag] no output [default: off]
-v|--verbose : [flag] also show debug messages [default: off]
-f|--force : [flag] do not ask for confirmation (always yes) [default: off]
-G|--GITPUSH : [flag] push to git after commit [default: off]
-I|--INDEX : [flag] build index.md if index.pre/.post present (for mkdox build) [default: off]
-Q|--SHORT : [flag] include short contents of page (for mkdox toc) [default: off]
-R|--RECURSIVE : [flag] also list subfolders (for mkdox toc) [default: off]
-T|--TREE : [flag] list as tree (for mkdox toc) [default: off]
-X|--EXPORT : [flag] export to PDF (for mkdox build) [default: off]
-l|--log_dir <?> : [option] folder for log files [default: /Users/pforret/log/mkdox]
-t|--tmp_dir <?> : [option] folder for temp files [default: /tmp/mkdox]
-D|--DOCKER <?> : [option] docker image to use [default: pforret/mkdox-material]
-E|--TITLE <?> : [option] set site title
-H|--HISTORY <?> : [option] days to take into account for mkdox recent [default: 7]
-L|--LENGTH <?> : [option] max commit message length [default: 99]
-P|--PORT <?> : [option] http port for serve [default: 8000]
-S|--SECS <?> : [option] seconds to wait for launching a browser [default: 10]
<action> : [choice] action to perform [options: new,serve,post,build,recent,toc,check,env,update]
<input> : [parameter] input folder name (optional)
<output> : [parameter] output file name (optional)