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.
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
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:
--title 'Things and Stuff'
= specify a title for the book. If not specified, the command will interactively ask for a title.
--ignore git
= Create a .gitignore
file. If not specified, the command will ask whether or not you want one.
--theme
= Create a theme/
directory with the files that make up the default theme. This is not normally needed unless you’re planning to modify the theme.
This creates the following files:
.gitigore
book/
book.toml
src/
src/SUMMARY.md
src/chapter_1.md
book.toml
configures the properties of the overall book itself, including any additional processing steps needed while building the book.
src/SUMMARY.md
contains the “structure” of the book, and is used to build the navigation bar on the left side of every page. The initial contents of the file reference a “Chapter 1”.
src/chapter_1.md
is a sample file. Deleting this file (and removing the reference to it from SUMMARY.md
) are usually the first things I do when setting up a new book.
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
IF the repo is going to be stored on a remote server, such as Github, Bitbucket, or Keybase…
In that remote server’s web interface, create an empty repo and get its URL.
Keybase doesn’t have a web interface, so use the command line to create the repo.
keybase git create xyzzy
On the local machine, add a “remote” pointing to the upstream repo’s URL.
git remote add origin git@github.com:username/xyzzy
git remote add origin keybase://private/username/xyzzy
Push the initial commit and tag.
git push -u origin main
git push --tags
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.
.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
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:
Some people may want to use the src/chapter_1.md
file, but I never do.
Edit src/SUMMARY.md
, remove the appropriate line. It looks like this:
- [Chapter 1](./chapter_1.md)
Stage the file to be committed.
git add src/SUMMARY.md
Use “git rm
” to remove the file.
git rm src/chapter_1.md
Commit and push the change.
$ git status
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: src/SUMMARY.md
deleted: src/chapter_1.md
$ git commit -m 'Remvoed chapter_1.md'
$ git push
2022-09-10 jms1
jms1.info
site from Apache to Keybase Sites and a typo caught my eye, so I gave it a quick once-over.2022-03-08 jms1