loading...
Cover image for Generate your own React Component using CLI by using Plop.js

Generate your own React Component using CLI by using Plop.js

abdulkareemtpm profile image ABDULKAREEM ・4 min read

Those who have previously worked in Angular may be noticed that the React ecosystem is not standardized as an Angular ecosystem. A new React app has nothing much. The directory and dependencies structures can be made as our own wish. That could be good, but that rise lack of uniformity amongst React developers.

We don't have a CLI command similar to angular-cli to generate a new component, the research to overcome this helped me to find plop.js.

What is Plop?
Micro-generator framework that makes it easy for an entire team to create files with a level of uniformity.

Let's Start coding...

Setting up your app

First, let’s create a new react app using create-react-app

npx create-react-app my-app

Once the app is successfully created, now change your working directory by running below command.

cd my-app

Installing plop.js

Install plop as a dev-dependency

npm install --save-dev plop

Setting up the project structure

We need to decide, what boilerplate you want to generate. Over the last few projects, I'm using the following structure for my React app.

Configuring plop

create a plopfile.js in your root app folder and add the below code.

const { readdirSync } = require("fs");

const getDirectories = (source) =>
    readdirSync(source, { withFileTypes: true })
        .filter((dirent) => dirent.isDirectory())
        .map((dirent) => {
            return { name: dirent.name, value: dirent.name };
        });

module.exports = (plop) => {
    let directories = getDirectories("src/pages");
    plop.setGenerator("component", {
        description: "Create a component",
        // User input prompts provided as arguments to the template
        prompts: [
            {
                // Raw text input
                type: "input",
                // Variable name for this input
                name: "name",
                // Prompt to display on command line
                message: "What is your component name?",
            },
            {
                // Raw text input
                type: "confirm",
                // Variable name for this input
                name: "isCommon",
                // Prompt to display on command line
                message: "Is it common component?",
            },
            {
                when: function (response) {
                    return response.isCommon === false;
                },
                // Raw text input
                type: "list",
                // Variable name for this input
                name: "container",
                // Prompt to display on command line
                message: "Choose container?",
                choices: directories,
            },
        ],
        actions: (data) => {
            const path = data.isCommon ? "src/common/" : "src/pages/" + data.container + "/";

            let actions = data.isCommon
                ? [
                        {
                            // Add a new file
                            type: "add",
                            // Path for the new file
                            path: path + "{{pascalCase name}}/{{pascalCase name}}.js",
                            // Handlebars template used to generate content of new file
                            templateFile: "plop-templates/Component/Component.js.hbs",
                        },
                        {
                            type: "add",
                            path: path + "{{pascalCase name}}/index.js",
                            templateFile: "plop-templates/Component/index.js.hbs",
                        },
                        {
                            type: "add",
                            path: path + "{{pascalCase name}}/{{pascalCase name}}.styled.js",
                            templateFile: "plop-templates/Component/styled.js.hbs",
                        },
                        {
                            type: "add",
                            path: path + "{{pascalCase name}}/{{pascalCase name}}.stories.js",
                            templateFile: "plop-templates/Component/stories.js.hbs",
                        },
                  ]
                : [
                        {
                            // Add a new file
                            type: "add",
                            // Path for the new file
                            path: path + "{{pascalCase name}}/{{pascalCase name}}.js",
                            // Handlebars template used to generate content of new file
                            templateFile: "plop-templates/Component/Component.js.hbs",
                        },
                        {
                            type: "add",
                            path: path + "{{pascalCase name}}/index.js",
                            templateFile: "plop-templates/Component/index.js.hbs",
                        },
                        {
                            type: "add",
                            path: path + "{{pascalCase name}}/{{pascalCase name}}.styled.js",
                            templateFile: "plop-templates/Component/styled.js.hbs",
                        },
                  ];
            return actions;
        },
    });

    plop.setGenerator("page", {
        description: "Create a page",
        // User input prompts provided as arguments to the template
        prompts: [
            {
                // Raw text input
                type: "input",
                // Variable name for this input
                name: "name",
                // Prompt to display on command line
                message: "What is your page name?",
            },
        ],
        actions: [
            {
                // Add a new file
                type: "add",
                // Path for the new file
                path: "src/pages/{{pascalCase name}}/{{pascalCase name}}.js",
                // Handlebars template used to generate content of new file
                templateFile: "plop-templates/Component/Component.js.hbs",
            },
            {
                type: "add",
                path: "src/pages/{{pascalCase name}}/index.js",
                templateFile: "plop-templates/Component/index.js.hbs",
            },
            {
                type: "add",
                path: "src/pages/{{pascalCase name}}/{{pascalCase name}}.styled.js",
                templateFile: "plop-templates/Component/styled.js.hbs",
            },
        ],
    });
};

Creating plop-templates

We need to create a plop-templates so that plop.js generates the new components based on that template.

Inside your root app folder create a new folder called plop-templates and create templates with .hbs extension indicates that this is a Handlebars.js template.

For my folder structure, I have four template files as follows:

1. Functional component

Functional Component

2. Styled Component

Functional Component

3. Storybook

Functional Component

4. index.js

Functional Component

Adding script to package.json

And lastly, we’ll want to add a script to our package.json to create an alias for the plop command.

"generate": "plop"

With this, our plop setup is complete now open your terminal and run npm run generate.

npm run generate

It prompts a question with two options component or page

If you choose component. Then,

npm run generate | component

After entering the component name and hitting enter key, it will prompt another question asking whether it is a common component or not. If you choose common, then the component will be generated under the common folder, else it maps the page folder, from where you could generate the component inside the respective page component.

generated component

If you were chosen page instead of component, then the resulting will be:

generated pagecomponent

Now that we’ve built out our component generator, we can build generators for Redux, Hooks, and services as well.

Thanks 🙌 for reading and happy coding!

Posted on Apr 7 by:

Discussion

markdown guide