Brian Han

How to Generate Blog Posts in Gatsby using Hygen

Table of Contents
Photo of big stamp by Hannes Wolf

Photo by Hannes Wolf on Unsplash

What is Hygen?

Hygen is this awesome code generator that creates files for you from your command line interface (CLI).

File Strutucture

For this site, I’m using the same file strutcture as gatsby-starter-blog. All my blogs live in the content/blog folder.

./content/blog
└── YYYY-MM-DD-my-blog-post-title
    ├── featuredImage.png
    └── index.md

Frontmatter

My frontmatter is the same as gatsby-starter-blog but I’ve also added my own keys.

index.md

---
title: "How to Generate Blog Posts in Gatsby using Hygen"
description: "Scaffold arbitrary folders, files and boilerplate code with Hygen."
date: "2019-01-04"
updated: "2020-05-18"
docz: false
featuredImage: "./stamp.jpg"
draft: false
---
Read more about frontmatter here
### Updated

A formatted date string to indicate when a blog was updated. But I'm going to omit this field whenever I create new blog posts.

### Docz

Boolean used in **gatsby-node.js** to distinguish `*.md` files that are for the blog vs for docz. Basically, I'm only querying for markdown so that docz files don't get published to the blog.

I'm using [docz](https://www.docz.site/) as an alternative to [storybook](https://storybook.js.org/) for documenting and prototyping components.

### featuredImage

A string path for the featured image used on the blog and the posts.

### draft

Boolean used to prevent unfinished blogs from being published.

Quickly Get Started with Hygen

Initialize Hygen and create a new generator called blog using npx.

npx hygen init self
npx hygen generator new --name blog

You should see a new _templates folder created at the root of your project.

_templates
├── blog
│   └── new
│       └── hello.ejs.t
└── generator
    ├── help
    │   └── index.ejs.t
    ├── new
    │   └── hello.ejs.t
    └── with-prompt
        ├── hello.ejs.t
        └── prompt.ejs.t

Edit _templates/blog/new/hello.ejs.t.

---
to: content/blog/YYYY-MM-DD-new-blog/index.md
---
---
title: "title"
description: "description"
date: "YYYY-MM-DD"
docz: false
featuredImage: "./featuredImage.jpg"
draft: true
---

Run the hygen command to create a new blog post.

npx hygen blog new

A new blog folder and file called YYYY-MM-DD-new-blog/index.md will be created.

content/blog
└── YYYY-MM-DD-new-blog
    └── index.md

From this point you can manually edit the folder names and frontmatter and start blogging!

But we can also use prompts in our CLI to make our hygen command a little smarter.

Create a CLI for Generating Blog Posts

Setup files

Create a prompts.js and slugify.js file in _templates/blog/new.

The prompt.js file will be used to show prompts in the terminal so we can generate a blog post with all the correct data upfront.

The slugify.js file is a helper function we’ll be using to slugify our titles to use as a folder name. Here’s a gist with the slugify code.

_templates/blog/new
├── hello.ejs.t
├── prompt.js
└── slugify.js

Getting inputs

In prompt.js, we give two input prompts to the prompt() method to capture title and description.

module.exports = {
  prompt: ({ prompter }) => {
    return new Promise((resolve, reject) => {
      prompter
        .prompt([
          {
            type: "input",
            name: "title",
            message: "Title?",
          },
          {
            type: "input",
            name: "description",
            message: "Description?",
          },
        ])
        .then(({ title, description }) => {
          console.log({ title, description });
        });
    });
  },
};

Using inputs for frontmatter data

Inside .then, we can generate date, slug, and folderName.

prompt.js

const slugify = require("./slugify");

module.exports = {
  prompt: ({ prompter }) => {
    return new Promise((resolve, reject) => {
      prompter
        .prompt([
          {
            type: "input",
            name: "title",
            message: "Title?",
          },
          {
            type: "input",
            name: "description",
            message: "Description?",
          },
        ])
        .then(({ title, description }) => {
          const date = new Date().toISOString().split("T")[0];
          const slug = slugify(title);
          const folderName = `${date}-${slug}`;

          resolve({
            title,
            description,
            date,
            folderName,
          });
        });
    });
  },
};

When the Promise from this prompt method resolves, that new data can be interpolated into hello.ejs.t, which is used as the template for creating index.md.

_templates/blog/new/hello.ejs.t

---
to: content/blog/<%= folderName %>/index.md
---
---
title: "<%= h.inflection.titleize(title) %>"
description: "<%= h.inflection.capitalize(description) %>"
date: "<%= date %>"
draft: true
docz: false
---

Also take note of the h.inflection helper functions; these come from hygen (see Helpers and Inflections). We’re using these to format title and description. It’s not perfect but works most of the time.

We’re done! Try it out!

Run the hygen command again.

npx hygen blog new

Or create an npm script.

# yarn add hygen -D
npm i hygen -D

package.json

{
  "create:blog": "hygen blog new"
}
npm run create:blog

Gotchas

The titleize and capitalize helpers work most of the time but be sure to double-check the strings in case you gave it a weirdly-cased word like “ESLint”, where it could come out as either “Eslint” or “eslint” respectively.

It would be nice if I could…

Resources