DEV Community

Cover image for Prepare your Rust API docs for Github Pages
Ben Lovy
Ben Lovy

Posted on

Prepare your Rust API docs for Github Pages

Rust comes with a built-in documentation system, rustdoc. It's great, use it.

Github comes with a built-in web hosting service, Github Pages. It's great, use it.

To use Github Pages, you can either create a directory in your repository to host your deployed web content or a separate branch and then activate the feature in the "Pages" section of your repository settings:

settings screenshot

Great!

You get a directory located at <project>/target/doc when you run cargo doc to generate your Rust documentation. It contains the complete web content ready to publish. If you execute cargo doc --open, your default browser will open up and show you what it generated.

Unfortunately, this folder can't be copied strictly as-is. If you try, you'll get a 404. This is because Github Pages is looking for an index.html file in the root directory of wherever it's pointed. However, cargo doc created a subdirectory for your crate specifically, where index.html lives. Here's my example for a Rust package called build_wheel:

$ tree target/doc/
target/doc
├── ayu.css
├── brush.svg
├── build_wheel
│  ├── all.html
│  ├── fn.build_wheel.html
│  ├── index.html          <-- RIGHT HERE
│  ├── sidebar-items.js
│  ├── struct.Config.html
│  └── struct.Tag.html
├── clipboard.svg
/* ... etc, etc... */
Enter fullscreen mode Exit fullscreen mode

Uh-oh, it's nested. Github can't find it. You can't just make a symbolic link to an index.html in the root directory because all the relative links inside will break.

Luckily, the fix is easy. You simply need to create an index.html that reroutes where you want. This file only consists of one line:

<meta http-equiv="refresh" content="0; url=build_wheel">
Enter fullscreen mode Exit fullscreen mode

This file uses the http-equiv meta attribute to point immediately to the build_wheel subdirectory and load the index.html file found there. Just replace the directory name with the name of your package.

You can easily automate this in a simple script:

cargo doc --no-deps
rm -rf ./docs
echo "<meta http-equiv=\"refresh\" content=\"0; url=build_wheel\">" > target/doc/index.html
cp -r target/doc ./docs
Enter fullscreen mode Exit fullscreen mode

Feel free to get as fancy as you want for pulling the actual name. I've just hardcoded it ¯\(ツ)/¯.

When Github Pages tries to build your content, now it will find this root index page. Users will load this page and immediately refresh the page you intended to display, and all the internal links generated by rustdoc will work as expected.

Neat.

Cover photo by Kelly Sikkema on Unsplash

Discussion (4)

Collapse
timclicks profile image
Tim McNamara

This is quite cunning. I like it.

Collapse
ssokolow profile image
Stephan Sokolow

It's also how I ensured no broken links when I was migrating the root ssokolow.com site to Jekyll.

Just have a bunch of folders containing redirecting index.html files named after the old non-HTML routes from when I was using MoinMoin. (eg. ssokolow.com/ContactMe )

Collapse
dystroy profile image
Denys Séguret

This is interesting but why not using docs.rs where all documentations are available as soon as you publish your crate ?

Collapse
deciduously profile image
Ben Lovy Author • Edited on

I'm using this for a crate that's part of a build process specific to one project. It's not likely to end up published, but I still want to provide accessible documentation. You're definitely right for most public packages, just use the existing infrastructure!