[jms1]
Creating a "book" with mdbook
John Simpson 2022-03-08 - Last updated 2022-09-10

I was in the process of writing a document at work last week, and realized that the Markdown file I was working on already had over 10,000 lines, and it was only about 60% done writing it. When I created a PDF to preview it, the PDF file had about 40 pages so far. I realized that I was “writing a book”, and that the document was too long for some people.

I’ve seen a lot of multi-page “documentation” web sites that all followed a common pattern, with a navigation bar on the left having a set of links to all of the pages making up the documentation. Many of these were hosted with sites like readthedocs.org or GitBook, however I needed a stand-alone tool which produced stand-alone files, because some of the information I’m documenting is proprietary and cannot be hosted outside the company.

I found a couple of programs which automate making these kinds of sites, and mdbook caught my eye. It’s written in Rust, and is used by the Rust developers to generate their own documentation.

I tried it out, and found it to be very easy to use - the hardest part for me was figuring out where to logically break that original Markdown file into separate pages. mdbook produced a set of static web pages that made the documentation a LOT easier for readers to navigate.

So now I’m using it at work, and I decided to convert my chicken-scratch notes about how to install it and set up a new book, into a document that I can refer to myself whenever I need to write a book, and which other people may find useful.

Install mdbook

The mdbook documentation explains several different ways to install the software. My personal and work machines both run macOS with Homebrew, so for me the process was very simple:

brew install mdbook

Create a new book

The mdbook init command creates a basic skeleton of the files it needs to build a “book”. You can run it in an empty directory and it will create its files there.

mkdir .../xyzzy
cd .../xyzzy
mdbook init --ignore git --title 'Things and Stuff'

It recognizes the following options:

This creates the following files:

.gitigore
book/
book.toml
src/
src/SUMMARY.md
src/chapter_1.md

Create a git repo

I use git to track almost everything I work on. When I create a book, I like having the initial commit in the repo contain the exact files generated by “mdbook init”.

cd .../xyzzy
git init -b main

At this point the repo has no commits, but you can run git status and see what files are ready to be committed.

$ git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    .gitignore
    book.toml
    src/

nothing added to commit but untracked files present (use "git add" to track)

No surprises, so use what we have as the initial commit.

$ git add .
$ git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
    new file:   .gitignore
    new file:   book.toml
    new file:   src/SUMMARY.md
    new file:   src/chapter_1.md

$ git commit -m 'Initial commit'

I also create an initial tag in each repo, pointing to the very first commit.

$ git tag -sm 'Tagging the initial commit' initial

Set up remote

IF the repo is going to be stored on a remote server, such as Github, Bitbucket, or Keybase…

If the repo doesn’t have a remote, you’ll need to be a lot more careful about not accidentally deleting the book or its .git/ directory.

Update .gitignore

The .gitignore file created by mdbook init contains the line book, so that git will ignore the book/ directory in the root of the repo. This is fine, but it also makes git ignore other files and directories whose names may be “book”. This should be changed so it only ignores the book directory in the root of the repo.

You should also add the names of any other files that git should ignore. I normally use something like this…

/book/
.DS_Store
._*
*~
*.bak

Commit and push the change.

git add .gitignore
git commit -m 'Updated .gitignore with the usual list'
git push

Template

For most of what I do at work, readers need to know which version of a “book” they’re looking at. mdbook doesn’t have a way to include any kind of version number, but it turns out to not be overly complicated to add this information.

I normally use a “template” to start new “books”. This template already includes the modifications to add git information (commit hash and possibly tags) to the pages. It also includes some other cosmetic tweaks I like to have in the documentation I write. This is all documented here:

Template

Working with mdbook

Removing “Chapter 1”

Some people may want to use the src/chapter_1.md file, but I never do.

Changelog

2022-09-10 jms1

2022-03-08 jms1

CC BY-SA 4.0
[hacker emblem]