Plop for auto generated content workflow

All Posts

Plop for auto generated content workflow

Updated: August 14, 2020 by Tony Alves

I've used yeoman-generator for some time now and wanted to try a new generator for my garden. I chose to try plop this time.

Note: Plop has an api that would allow for items to be created dynamically during CI/CD, but we will get into that in a later post. In summary, plop is just a tool that takes inquirer prompts and glues them to handlebars templates.

Let's get into this!

Steps we'll take

  • Install plop into our package
  • Create the shell of our plop workflow
  • Create a template
  • Add new prompts for the template
  • Use a helper function to get a date format for our file name

Install plop into our package

Let's install plop into our project package.

yarn add plop@latest --dev

OR

npm install plop@latest --save-dev

Using a monorepo with yarn workspaces, then you will add it at the root of your repository.

yarn add plop@latest --dev --ignore-workspace-root-check

Create the Plopfile

Create a file called plopfile.js at the root of the project.

module.exports = function (plop) {
// create your generators here
plop.setGenerator('garden', {
description: 'this is a skeleton plopfile',
prompts: [], // array of inquirer prompts
actions: [] // array of actions
});
};

Now we'll just create the generator to only write out a simple template file (below) into our garden.

module.exports = function (plop) {
// create your generators here
plop.setGenerator('garden', {
description: 'Create an entry into the Digital Garden',
prompts: [
{
type: 'input',
name: 'slug',
message: 'slug name of post (will be part of file name)',
},
],
actions: [
{
type: 'add',
path: 'garden/posts/{{slug}}.mdx',
templateFile: 'plop-templates/garden.hbs',
},
],
});
};

Create a template

Plop uses handlebars for it's templates, so we'll put our template plop-templates/garden.hbs in our project. This is great news, because handlebars is quite mature and has a powerful api.

plop-templates/garden.hbs

---
draft: {{draft}}
title: {{title}}
path: /garden/{{slug}}
date: {{date}}
author: talves
description: >-
{{description}}
categories:
- 'draft'
keywords:
- 'new'
- 'garden'
garden: {{garden}}
image: '/images/social/{{slug}}.png'
---
## Just a simple H2

Add new prompts for the template

Here are the prompts for our template:

  • draft

    The draft prompt is of type list and allows for a boolean value defaulting to true.
    {
    type: 'list',
    name: 'draft',
    default: 'true',
    choices: ['true', 'false'],
    },
  • title

    {
    type: 'input',
    name: 'title',
    message: 'enter title:',
    },
  • slug

    The slug prompt allows for entry using spaces and will replace any spaces with a dash -.
    {
    type: 'input',
    name: 'slug',
    message: 'slug name of post (will be part of file name)',
    filter: val =>
    val ? val.toLowerCase().replace(/ /g, '-') : 'new-entry',
    },
  • date

    The date prompt allows for an empty entry for current system date time. Also converts to the ISO format.
    {
    type: 'input',
    name: 'date',
    message: 'enter post date:',
    filter: val => {
    const date = val ? new Date(val) : new Date(Date.now());
    return date.toISOString();
    },
    },
  • description

    {
    type: 'input',
    name: 'description',
    message: 'enter description:',
    },
  • garden

    Again, we have a list for the garden status with three items and a default. The default value is always pointed to for fast entry by just pressing enter.
    {
    type: 'list',
    name: 'garden',
    message: 'enter status of this entry today:',
    default: 'sprout',
    choices: ['sprout', 'sapling', 'evergreen'],
    },

Helper function for our file name prefix

Here is the helper function for the file name prefix (YYYY-mm-dd). We use this in our template passing in the date entered to build the prefix.

  • fileDate

    plop.setHelper('fileDate', function(date) {
    return new Date(date)
    .toISOString()
    .replace(
    /^(?<year>\d+)-(?<month>\d+)-(?<day>\d+)T.*$/,
    '$<year>-$<month>-$<day>',
    );
    });

Completed code

Here is the completed code for plopfile.js

module.exports = function(plop) {
// helper functions
plop.setHelper('fileDate', function(date) {
return new Date(date)
.toISOString()
.replace(
/^(?<year>\d+)-(?<month>\d+)-(?<day>\d+)T.*$/,
'$<year>-$<month>-$<day>',
);
});
// create your generators here
plop.setGenerator('garden', {
description: 'Create an entry into the Digital Garden 🖋',
prompts: [
{
type: 'list',
name: 'draft',
default: 'true',
choices: ['true', 'false'],
},
{
type: 'input',
name: 'slug',
message: 'slug name of post (will be part of file name)',
filter: val =>
val ? val.toLowerCase().replace(/ /g, '-') : 'new-entry',
},
{
type: 'input',
name: 'date',
message: 'enter post date:',
filter: val => {
const date = val ? new Date(val) : new Date(Date.now());
return date.toISOString();
},
},
{
type: 'input',
name: 'title',
message: 'enter title:',
},
{
type: 'input',
name: 'description',
message: 'enter description:',
},
{
type: 'list',
name: 'garden',
message: 'enter status of this entry today:',
default: 'sprout',
choices: ['sprout', 'sapling', 'evergreen'],
},
],
actions: [
{
type: 'add',
path: 'www/site/garden/posts/{{fileDate date}}-{{slug}}.mdx',
templateFile: 'plop-templates/garden.hbs',
},
],
});
};

Done!

Add your command to the scripts section of your package.

"scripts": {
"new": "plop garden"
},

Then you can run your command to start plop

yarn new

or

npm run new

This gives a quick scaffold of a new post and saves the time of copy paste and changing field values. There are some improvements that can be made here, but for now we'll call this finished and add improvements here when they are made.

© Tony Alves