Writing Static Site Generator Compatible Markdown
Intro
Static Site Generators (SSG's) like Gatsby, Astro, 11ty and Docusaurus (among others) are great for transforming your Markdown files into web pages. But there are a couple things that can trip you up while transferring your files between these generators. Let's work out how to configure our Markdown files library for maximum compatibility between static site generators.
Frontmatter
First it's important to understand what Frontmatter is and how it works. Every static site generator uses it, and it's not technically part of the Markdown standard.
Frontmatter is the metadata that you want to associate with a Markdown file. It's placed in the head of the file and is denoted by ---
Here is an example of Frontmatter.
---
title: "React: Modals With Portals"
date: "2020-10-16T07:04:03.284Z"
description: "Modals can be surprisingly tricky in React, but there is a good way to make them using Portals."
categories: ["Web Development"]
tags: ["React", "Modal", "Portals", "Twitch Clone"]
featuredImage: ../../assets/react-logo.png
---
This is actually something called YAML. It is described as "a human-friendly data serialization language for all programming languages.". YAML is used in many contexts, however within Markdown files and static site generators it is used to provide meta data for the file. It's important to understand a couple things. This is not Markdown, and it has a pretty loose official syntax. Not all variations of this syntax are compatible with all SSG's out of the box.
Additional Frontmatter Formats
Just a quick note, there are other frontmatter formats that some SSG's support. Such as TOML. YAML is just the most common.
Dates
One of the things I discovered while trying to transfer my markdown files to other SSG's is that they didn't like how my timestamp was formatted. Here is the YAML specification for timestamps:
Timestamp Language-Independent Type for YAML™ Version 1.1
This format works in Gatsby
date: "2023-03-14T00:00:00.000Z"
But if you try to use this format in Astro it will literally crash your build. Astro prefers
date: "2023-03-14"
Docusaurus will take the full date... but only if it's not wrapped in a string
date: 2023-03-14T00:00:00.000Z
You can customize how frontmatter is formatted in Astro, but that's not really the point. It should parse valid YAML out of the box, and it doesn't. If you want to avoid headaches in the future, consider using the simpler format. Gatsby appears to have no problem parsing either of these formats or many others.
Categories and Tags (arrays)
It's common in frontmatter to include arrays of tags and categories. Technically the following are both valid YAML formats for arrays
tags: ["Markdown", "Gatsby", "Astro", "11ty", "Docusaurus"]
tags:
- Markdown
- Gatsby
- Astro
- 11ty
- Docusaurus
But several SSG's will only accept the latter
tags:
- Markdown
- Gatsby
- Astro
- 11ty
- Docusaurus
So consider using that format. Gatsby works with both.
Final Recommended Format
---
title: "Some Title"
description: "All text strings wrapped in parentheses"
date: 2023-03-14
tags:
- Markdown
- Gatsby
- Astro
---
Remember that none of these YML tags are part of the CommonMark standard, so you can really add any tag you want in the frontmatter and then choose what to do with it later using your SSG. For example Gatsby doesn't bother with a slug frontmatter because it just uses the folder name as the slug.
Automating Frontmatter Conversion
If you find yourself in a situation like me where you have hundreds of files with frontmatter that you need to modify the format of, it's possible to automated this process. For example I asked ChatGPT to write me a python script that copies markdown files and modifies their frontmatter format.
import os
import yaml
import glob
import shutil
import frontmatter
# Path to the directory containing markdown files
markdown_dir = '/path/to/markdown/files'
# Path to the directory where updated files will be saved
output_dir = '/path/to/output/directory'
# Create the output directory if it doesn't exist
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# Get a list of all markdown files in the directory
markdown_files = glob.glob(markdown_dir + '/*.md')
# Loop through each file
for file in markdown_files:
with open(file, 'r') as f:
# Parse the YAML frontmatter
front_matter, content = frontmatter.parse(f.read())
# Reformat the values in the frontmatter
new_front_matter = {}
for key, value in front_matter.items():
if isinstance(value, str):
new_front_matter[key] = value.strip()
else:
new_front_matter[key] = value
# Create the output file path
output_file = os.path.join(output_dir, os.path.basename(file))
# Update the frontmatter in the output file
new_content = frontmatter.dumps(new_front_matter) + content
with open(output_file, 'w') as f:
f.write(new_content)
# Copy the original file's permissions to the new file
shutil.copymode(file, output_file)
I haven't actually tried it, but if I needed to really complete this task on hundreds of items I would go this route. Therefore don't let this all stress you out too much. Just use the recommended format for whatever your SSG is.
Relative Link Paths (images)
Consider the following file structure.
blog
├── post-title-one
│ ├── index.md
│ ├── 1.png
│ └── 2.png
└── post-title-2
├── index.md
├── 1.jpg
├── 2.jpg
└── 3.jpg
Note that we are packaging the images with our Markdown files and we can then reference them with relative links in the document like so
![image description](1.png)
This is in my opinion the ideal format for markdown documents, and I would argue this is the defacto standard. This works with the built in Markdown preview of VSCode, this works on Github, it works with Gatsby.
It does not however work with some SSG's like Astro. If you really want to ensure maximum compatibility you may want to consider hosting all your images in something like an S3 bucket and using absolute path links to images in your Markdown files. Although this comes with a whole host of other downsides and feels a bit like giving in to terrorists.
Comments
Recent Work
Basalt
basalt.softwareFree desktop AI Chat client, designed for developers and businesses. Unlocks advanced model settings only available in the API. Includes quality of life features like custom syntax highlighting.
BidBear
bidbear.ioBidbear is a report automation tool. It downloads Amazon Seller and Advertising reports, daily, to a private database. It then merges and formats the data into beautiful, on demand, exportable performance reports.