Building a Custom Static Site Generator for Technical Documentation

Victor UzoagbaVictor Uzoagba
5 min read

Introduction

What is a Static Site Generator (SSG)?

A Static Site Generator (SSG) is a tool that converts plain text files (like Markdown) into a complete static website. The output is a set of static HTML pages, which are fast to load and easy to host. Static sites are great for technical documentation because they don’t need a server to run, and they can be easily deployed anywhere, like on GitHub Pages or Netlify.

Why Build a Custom SSG?

While there are many great SSGs available like Jekyll, Hugo, and Next.js, building a custom one offers several advantages:

  • Flexibility: You control all the features and can tailor them to your documentation needs.

  • Simplicity: A custom SSG can be much simpler, focusing only on what you need, avoiding unnecessary features.

  • Learning: Building your own SSG helps you understand how documentation websites work behind the scenes.

Prerequisites

Before you start, you should be familiar with:

  • Basic JavaScript (or Python if you prefer that language)

  • How to write Markdown (a simple syntax for writing formatted text)

  • Basic HTML for creating web pages

Project Setup

Choosing a Language

We’ll use JavaScript (Node.js) for this tutorial because of its flexibility and popularity. If you prefer Python, you can follow similar steps using Python’s tools.

Setting Up Your Development Environment

  1. Install Node.js:

    • Download and install Node.js from the official website nodejs.org.
  2. Set up the project folder:

    • Create a new folder for your project. Open your terminal and run:

        mkdir custom-ssg
        cd custom-ssg
      
  3. Initialize the project:

    • Run the following command to create a package.json file:

        npm init -y
      

Installing Required Tools

For this project, you will need a couple of npm packages:

  • marked: A library to convert Markdown to HTML

  • fs-extra: A library for working with files and directories

Install them by running:

npm install marked fs-extra

Core Components of the SSG

Markdown to HTML Conversion

We’ll use marked to convert our Markdown files into HTML.

  1. Create a sample Markdown file: Inside your project folder, create a content folder and add a index.md file:

     ├── content
     │   └── index.md
    

    Add some Markdown content to the index.md file:

     # Welcome to My Documentation Site
     This is an example of technical documentation.
    
  2. Write the conversion script: Create a build.js file in the project root. This script will read the Markdown file, convert it to HTML, and save the result:

     const fs = require('fs-extra');
     const marked = require('marked');
    
     async function build() {
       // Read the Markdown file
       const markdown = await fs.readFile('./content/index.md', 'utf-8');
    
       // Convert Markdown to HTML
       const html = marked(markdown);
    
       // Create the output directory if it doesn't exist
       await fs.ensureDir('./dist');
    
       // Write the HTML file to the output directory
       await fs.writeFile('./dist/index.html', html);
    
       console.log('Site built successfully!');
     }
    
     build();
    
  3. Run the build:

    • Run the following command in your terminal to generate the HTML:

        node build.js
      
    • You should now have an index.html file inside a dist folder.

Template Engine

Instead of generating plain HTML, we want a consistent layout for all pages (e.g., with a header and footer). To achieve this, we’ll add a simple template system.

  1. Create a basic HTML template: Add a new file template.html:

     <!DOCTYPE html>
     <html lang="en">
     <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>My Documentation Site</title>
       <link rel="stylesheet" href="style.css">
     </head>
     <body>
       <header>
         <h1>Documentation Site</h1>
       </header>
    
       <main>
         {{ content }}
       </main>
    
       <footer>
         <p>© 2024 My Documentation</p>
       </footer>
     </body>
     </html>
    
  2. Modify the build script: Update build.js to insert the converted HTML into the template:

     async function build() {
       // Read the Markdown file
       const markdown = await fs.readFile('./content/index.md', 'utf-8');
    
       // Convert Markdown to HTML
       const content = marked(markdown);
    
       // Read the HTML template
       const template = await fs.readFile('./template.html', 'utf-8');
    
       // Insert the content into the template
       const finalHtml = template.replace('{{ content }}', content);
    
       // Write the HTML file to the output directory
       await fs.ensureDir('./dist');
       await fs.writeFile('./dist/index.html', finalHtml);
    
       console.log('Site built successfully!');
     }
    
     build();
    

Automating Build Process

Creating a Build Script

Our build.js script is already converting Markdown to HTML, but let’s improve it by processing multiple files.

  1. Add multiple Markdown files: Create a few more Markdown files in the content folder.

     ├── content
     │   └── index.md
     │   └── guide.md
    
  2. Modify the script to handle multiple files:

     async function build() {
       const files = await fs.readdir('./content');
    
       for (const file of files) {
         const markdown = await fs.readFile(`./content/${file}`, 'utf-8');
         const content = marked(markdown);
         const template = await fs.readFile('./template.html', 'utf-8');
         const finalHtml = template.replace('{{ content }}', content);
    
         const outputFileName = file.replace('.md', '.html');
         await fs.writeFile(`./dist/${outputFileName}`, finalHtml);
       }
    
       console.log('Site built successfully!');
     }
    
     build();
    

Handling Navigation

You can now add links between pages by manually adding them to your Markdown files.

Advanced Features

Search Functionality

For simple static search, you can use Lunr.js or Algolia to index the content. However, this requires some extra coding, which we can add later as an enhancement.

Syntax Highlighting for Code Blocks

To highlight code snippets, use Prism.js or highlight.js in your template’s <head> section.

Deployment and Hosting

Generating the Final Build

Now that your static site is ready, let’s deploy it!

Hosting Options

  • GitHub Pages: You can host your static site for free on GitHub Pages. Simply push your dist folder to your GitHub repository’s gh-pages branch.

  • Netlify or Vercel: These platforms allow for continuous deployment with just a few clicks. Once you connect your GitHub repository, it will automatically deploy the latest changes.

Conclusion

Review of the SSG Workflow

We’ve built a basic custom Static Site Generator using Node.js. You now have a working system that converts Markdown files into a static website with a consistent layout.

Potential Enhancements

You could extend this project by adding:

  • A search bar

  • Automatic navigation menus

  • Plugin support for additional features

0
Subscribe to my newsletter

Read articles from Victor Uzoagba directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Victor Uzoagba
Victor Uzoagba

I'm a seasoned technical writer specializing in Python programming. With a keen understanding of both the technical and creative aspects of technology, I write compelling and informative content that bridges the gap between complex programming concepts and readers of all levels. Passionate about coding and communication, I deliver insightful articles, tutorials, and documentation that empower developers to harness the full potential of technology.