3 minute read

GitBook is used all over the place, particularly with open source projects. Though lately folks have been moving away from the service and using other alternatives. One such example is with the kube-builder project. I was pretty familiar with using GitBook and was asked by a colleague to help with a bug. The bug was requesting that a banner be added to the v1 docs (that were using GitBook) and redirect folks to the new site. Easy enough, right? It should be a single line of code. But it turns out modifying the a GitBook theme is not that simple. Below are my notes on how we went about solving this issue.

Disclaimer: As with most of my posts, the write up is mostly going to be my rambly notes, if you would like more information please reach out.

The gist of how to override any GitBook is to create your own theme, publish it on NPM, add it to the GitBook’s build. Here are steps you can follow.

Special shout-out to Martin Hickey for giving me a shoutout in his PR

1. Use book.json instead of .gitbook.yaml

To build the GitBook locally you need the GitBook CLI, which is unsupported and only worked on Node v12 (more on this below). This version of GitBook reads the book config from a book.json file, not .gitbook.yaml that is used today.

A .gitbook.yaml that was used for my sample repo.

root: ./docs/

structure:
  readme: README.md
  summary: SUMMARY.md

The corresponding book.json (we will add to this later).

{
    "root": "/docs"
}

2. About the gitbook CLI

As mentioned earlier, the gitbook CLI has been unsupported for some time and appears to have stopped working in v12 of Node.js. If you try to compile and build a GitBook with Node.js v14 or v16 you’ll get a TypeError: cb.apply is not a function exception.

There are many ways around this problem in the issues and StackOverflow article I linked but the easiest way I found to workaround it was to just use a backlevel version of Node.js using n to do my Node.js version management.

If you don’t already have n, install it with:

npm install -g n

And swith to whatever Node.js version you’d like, for instance:

n install 12

Once your Node version is set appropriately you can install the gitbook CLI.

npm install -g gitbook-cli

And use that to build the site locally:

gitbook install

And to check it out on localhost:9000 run the following:

gitbook serve .

Once you’ve got that working locally you can build a custom theme and test it out.

3. Build a custom theme

For my example check out this repo

Based on my experience, the layout.html and page.html were required in the _layouts directory. I also couldn’t figure out a way to have the files inherit from their parent, so I copy and pasted the entire original theme. (Check it out here)

.
├── .github
   └── workflows
       └── npm-publish.yml
├── README.md
├── _layouts
   └── website
       ├── layout.html
       └── page.html
├── package-lock.json
└── package.json

At this point you can change the layout.html or page.html templates however you’d like. In my example we just added the following line to page.html

<h3>Viewing legacy documentation for kubebuilder, check out the <a href="https://book.kubebuilder.io">latest</a> documentation instead.</h3>

The one thing worth noting is that GitBook plugins follow a strict naming convention. They must start with gitbook-plugin-. So your repo name can be whatever you’d like but your published package on NPM must follow that convention or the gitbook install command will not be able to find your plugin.

The package.json for my example:

{
  "name": "gitbook-plugin-stevemar-archive",
  "version": "0.2.2",
  "description": "A test for adding archives",
  "engines": {
    "gitbook": ">1.x.x"
  },
  "gitbook": {
    "properties": {}
  }
}

Oh, also, if you’re not sure how to publish to NPM, there’s an easy GitHub Action for that. I had used it for the first time and was able to publish a package in about 15 minutes.

4. Using the extension in the GitBook

Assuming you’ve been able to publish a package to NPM you can now pull in your extension to your GitBook, to do that modify the book.json file to include the plugin. For example:

{
    "root": "/docs",
    "plugins": [ "stevemar-archive" ]
}

In this case, it’ll look for a package called gitbook-plugin-stevemar-archive on NPM.

Build the site locally, and pull in any plugins:

gitbook install

Check out the site locally:

gitbook serve .

Done!

Updated: