Creating Custom Generators in PlopJS

Plop.js is a powerful tool that allows you to create custom generators for your project. It can be used for creating new files, modifying existing files, and more. You can easily generate new code or any file in a consistent way, so you always have a consistent way to do something in your codebase.

In this article, I'm going to show you how to use Plop.js in a React project for generating component files and other files you usually need in a React project. Remember, you can easily integrate Plop.js into any Node project you want.

Creating a new React project

The first thing we need to do is create a new React project. You can easily add Plop.js to an existing project, but for the sake of this tutorial, we will use a new, fresh React project instead.

So, let's run this command on cli to create a new React project.

# Create new react app
pnpm create vite react-plop --template react-ts

After the scaffolding is completed, we will change the working directory to the new project we already created and install the required dependencies.

# Change working directory to root of app
cd react-plop
# Install dependencies
pnpm install

Installing Plop.js as dev dependencies

Now let's install Plop.js as devDependencies so we can use it in our project.

pnpm add plop -D

When you finished installing Plop.js now we can create plopfile.js in the root folder of our project, and in this file we can define our configuration for our generators.

Creating generator

Creating generator configuration

Now we will define our configuration for our generators in the plopfile.js file. Here is a simple example configuration you can put in the plopfile.js file before we can start generating our files.

// plopfile.js
export default (/** @type {import('plop').NodePlopAPI} */ plop) => {
  plop.setGenerator('component', {
    // Generator description
    description: 'Generate new component',
    // Prompts that will appear when the plop command is executed
    prompts: [
      {
        // Type of prompt
        // There are many types you can use, for example: input, number, confirm, etc
        // We'll use the input type here because we want to accept a string input for the component name
        type: 'input',
        // The name to use when storing the answer
        // We can access the prompt value using the name provided here.
        name: 'name',
        // Question to print in cli
        message: 'Input your component name',
      },
    ],
    // Actions to take after all data required to generate a new file is available
    actions: [
      {
        // Type of action
        // Other types, such as addMany, modify, and append, can also be used, or you can create your own action.
        type: 'add',
        // Location for the new file
        path: 'src/components/{{ name }}.tsx',
        // Template file location
        templateFile: 'templates/component.hbs',
      },
    ],
  })
}

Creating component template

Plop.js using handlebars as templating system, you can easily pass data you get in the prompt to the template file you are using in actions.

Now we're going to create a new template file for the content of the component file we want to generate. Let's create a new file in templates/component.hbs.

Put this code in the new file we already created.

export const {{ pascalCase name }} = () => {
  return <div></div>
}

Here we define a basic code for react component, you can put any code you need in this file.

Notice the {{ pascalCase name }} ? Here we are using the value we get in prompt for the component name.

The pascalCase is a case modifier helper, so we can convert the value we get in the prompt to another naming case. Here, I want my component name to use a Pascal case name, so I'm using this case modifier.

Adding plop command to package.json

Now, after configuring our generator in plopfile.js, we will add a command in package.json in the script section like this.

// package.json
{
    ...,
    "scripts": {
        "plop": "plop"
    },
    ...
}

Running the command

After adding the plop command to the package.json file, we can start running our generator using this command.

pnpm plop

When you run the command in your cli, you will see the prompt asking you for the component's name. Just type the name you want for your component and press enter. Wait for seconds, and if it is successful, you will see a new component in src/components.

Adding other files to generate

Besides generating component files, maybe you also want to simultaneously generate test files and also CSS files that are still related to components. You can also easily add other files, such as a test file and a CSS file, by adding a new item to actions in plopfile.js.

Let's add new actions for generating a test file and a CSS file.

// plopfile.js
{
  ...,
  actions: [
      {
        type: 'add',
        path: 'src/components/{{ name }}.tsx',
        templateFile: 'templates/component.hbs',
      },
      // New action for adding test file and css file
      {
        type: 'add',
        path: 'src/styles/{{ name }}.css',
        templateFile: 'templates/component-css.hbs',
      },
      {
        type: 'add',
        path: 'src/test/{{ name }}.test.tsx',
        templateFile: 'templates/component-test.hbs',
      },
    ],
}

And let's create new template for our css and test file.

/* template/component-css.hbs */

/* We will using the name we get from prompt as css class here */
.{{ kebabCase name }} {
  /* Add your css here */
}

// templates/component-test.hbs

// Import generated component located at 'components' folder
import {{ pascalCase name }} from '../components/{{ name }}.tsx'

// {{ name }} is the 'name' of value from prompt, we will use it to describe our test here
describe('{{ name }}', () => {
  it('should work', () => {
    // Add your test here
  })
})

After adding the new template for CSS and test files for our generator, let's try to run plop command again.

pnpm plop

If there's no mistake, you can find three new files in their respective locations in src/components, src/styles, and src/test.

You may notice in the test file we successfully generated that there's a typescript error. That error happens because we have not yet installed any test frameworks like vitest or jest, so you can ignore this error now and add your preferred test framework later.

Conclusion

After reading this article, I hope you know a better way to create new files automatically using Plop.js so you can save time by reducing the amount of boilerplate you need to write and increase your coding productivity.

Just in case you want to know how to handle multiple generators, modify files, or perform other more complex functions using Plop.js, you can refer to the bulletproof react example to see how it works.