Marshall Bowers

Conjurer of code. Devourer of art. Pursuer of æsthetics.

Zed Docs: Powered by Cloudflare Workers

Saturday, May 4, 2024
610 words
4 minute read

The Zed docs have been in need of some infrastructural love for a while.

The existing setup for the docs entailed manually replicating changes from the source files—stored in the Zed repo—to a separate repo for zed.dev.

As you might imagine, this setup came with a number of issues:

  1. Having to manually replicate the docs was annoying, error-prone, and resulted in docs being frequently outdated
  2. Contributors couldn't see the zed.dev repo on account of it being private, meaning that docs changes were essentially being made blind

To solve this, we simplified our docs pipeline using mdBook to render the docs. This provided us with an easy way to build and deploy a static site for the docs, as well as a local development server that could be used by anyone to preview docs changes.

However, one question remained: how would we get these docs to live at zed.dev/docs?


I've used Cloudflare Workers in the past to stitch multiple sites together with great success, so I suggested we leverage it here again.

The first order of business was to get the docs deployed somewhere. Since we're already using Cloudflare for everything else in this setup, Cloudflare Pages seemed like an obvious choice.

The one trick here is that we needed to deploy the docs at the /docs path instead of at the root path.

We can set the site-url in the book.toml for mdBook:

[book]
site-url = "/docs/"

And then when deploying use the --dest-dir flag to place the built artifacts into a docs/ subdirectory:

mkdir -p target/deploy
mdbook build ./docs --dest-dir=../target/deploy/docs/
pages deploy target/deploy --project-name=docs

Now when we deploy the docs they'll be hosted at the-docs.pages.dev/docs1.

With the docs deployed to Cloudflare Pages, we needed a Cloudflare Worker to route requests there from zed.dev.

The Worker doing the heavy lifting here is incredibly simple:

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    url.hostname = 'the-docs.pages.dev';

    let res = await fetch(url, request);

    if (res.status === 404) {
      res = await fetch('https://zed.dev/404');
    }

    return res;
  },
};

This Worker will take the incoming request, change the hostname to the Pages deployment (the-docs.pages.dev), and then proxy the request to its new destination.

If we get a 404 response back from the docs, we then forward the request to https://zed.dev/404 so that we get back our regular 404 page instead of a the mdBook one. Otherwise, we just return the response as-is.

We then setup a Workers route to forward traffic under zed.dev/docs* to the Worker. This means that any requests beneath /docs will go through the Worker, while the rest of our traffic is left untouched.

The end result of this is that, for all intents and purposes, it appears that the /docs is a part of the entire zed.dev site while being able to be deployed independently to a separate location.


And that's pretty much all there is to it.

Cloudflare Workers has once again proved itself as an invaluable tool to have in my web toolbox. Every time I use a Cloudflare product it really does feel like magic. But there's no magic here; just some excellent engineering by the folks over at Cloudflare.

Right now the new docs live at zed.dev/docs2, but they'll be promoted to zed.dev/docs early next week.

I'm looking forward to writing more docs in this streamlined setup.

1

the-docs.pages.dev is an example domain for illustrative purposes. The real pages.dev URL is slightly different.