Gatsby Content from AsciiDoc

AsciiDoc is a powerful format for authoring content. Like Markdown it’s simple to use, but offers more features and flexibility. In this post I’ll look at how to adapt a Gatsby site to use AsciiDoc.

🚀 TL;DR Show me the code. Look at the 2-asciidoc branch. This site is deployed here.

Starter Project

The Gatsby Starter Project has content pages implemented as JavaScript files. Specifically, there are three files:

  • index.js
  • page-2.js and
  • page-3.js.

During the build process these are transformed into static HTML.

This is not ideal. Content is not code. Having to write code for each new piece of content is just another source of friction in the writing process. Wouldn’t it make more sense to write content in a more suitable format?

Markdown is IMHO the best option for site content. There are many flavours of markdown. The one that we will consider now is AsciiDoc, which has a number of features which make it well particularly suited to writing documentation.

Asciidoctor & Gatsby

Asciidoctor is a text processor that translates AsciiDoc markdown into HTML5. Asciidoctor is implemented in Ruby, however, there is a JavaScript port, Asciidoctor.js. We won’t need to worry about integrating Asciidoctor.js into our Gatsby site though because there’s a transformer, gatsby-transformer-asciidoc, to do that.

Install

Add gatsby-transformer-asciidoc as a dependency in package.json. Update dependencies.

Configure

Add gatsby-transformer-asciidoc to gatsby-config.js as a plugin:

plugins: [`gatsby-transformer-asciidoc`]

You can also specify one or more options if you need to tweak the default setup.

plugins: [
  {
    resolve: `gatsby-transformer-asciidoc`,
    options: {
      attributes: {
        showtitle: true,
        icons: "font"
      },
      fileExtensions: [`adoc`, `md`],
    }
  }
]

Add AsciiDoc Content

We’ll put the AsciiDoc source into a dedicated content directory. Create three files:

  • content/what-is-asciidoc.adoc
  • content/what-is-gatsby.adoc and
  • content/what-is-tailwind.adoc.

The content for the landing page can still be found in src/pages/index.js. This is the only page which is implemented in JavaScript. The content for the remaining pages is all specified using AsciiDoc.

Where to Find AsciiDoc Content?

We need to tell Gatsby where it will find the AsciiDoc content. To do this we’ll add another gatsby-source-filesystem plugin entry in gatsby-config.js:

{
  resolve: "gatsby-source-filesystem",
  options: {
    name: "docs",
    path: `${__dirname}/content/`,
  },
}

Install & Configure Tailwind CSS

This is not really necessary but it’s a very handy thing to do. Tailwind will take a lot of the pain out of styling your site.

Follow the guide here, which will instruct you to install the tailwindcss and postcss packages. While you’re about it, install the @tailwindcss/typography plugin too.

There are two configuration files linked to Tailwind and PostCSS:

  • tailwind.config.js (where are the files that use the Tailwind classes?) and
  • postcss.config.js (informs PostCSS of the tailwindcss package).

The Tailwind CSS is included by placing the following directives to the existing site CSS file:

@tailwind base;
@tailwind components;
@tailwind utilities;

💡 You won’t see Tailwind CSS files being explicitly included in your site. They will be bundled into the commons.css file which is linked into all pages.

Add Layout

The files in the src/layouts directory define the layout of page contents. They provide a consistent structure to multiple pages of the site. A page layout is defined in src/layouts/index.js.

Gatsby test site landing page. Gatsby test site 'What is Gatsby?' page.
Gatsby test site 'What is AsciiDoc?' page. Gatsby test site 'What is Tailwind?' page.

💡 The dedicated src/layouts directory is no longer a special or required directory in a Gatsby project. Layout components can now be defined anywhere.

Add Template

Whereas a layout specifies the high level structure of pages, a template dictates how the page content is incorporated into the layout. Since we are using AsciiDoc to write the site content, our template needs to tell Gatsby how to translate the AsciiDoc content into page content.

Templates work in conjunction with GraphQL. A GraphQL query fetches the data from each of the AsciiDoc files and then the template controls how that content is rendered on the page.

A page template is defined in src/templates/article.js. This is where we set up the footer content on each of the AsciiDoc pages, where the author and revision information are extracted from the AsciiDoc header.

Add a Head

The default <head> content generated by Gatsby is sufficient to get started. However, you’ll normally want to insert more content (like SEO tags) into the <head>. Use the Head API.

We export Head from src/templates/article.js and it sets a couple of SEO tags, populating them dynamically with content from the GraphQL query.

GraphQL

If you fire up a development server and head to http://localhost:8000/___graphql then you can use the GraphiQL interface to create and run GraphQL queries on the site.

GraphQL query explorer.

Now that we have added AsciiDoc functionality you’ll see a few new top level fields, namely allAsciidoc and asciidoc. The former is used to generate a list of all AsciiDoc pages in gatsby-node.js, while the latter is used for extracting page-specific content in the template.

Render AsciiDoc to HTML

Now it’s time to pull this all together. The final changes are made to gatsby-node.js, which exports a createPages(). This function uses a GraphQL query (the same one illustrated in the GraphiQL screenshot above) to extract information on each of the AsciiDoc pages. For each page the createPage method is run, which generates the corresponding static HTML.

Conclusion

Using AsciiDoc makes the process of writing site content smoother and easier. The code for this post can be found here and the deployed site is here.