DEV Community 👩‍💻👨‍💻

Cover image for Create react components at the speed of light with Plop.js
Ivan
Ivan

Posted on • Updated on

Create react components at the speed of light with Plop.js

So you are working in your React app, and it comes the time to create a new component, you already have your ritual down. Go to the components folder, create an index file, create another file for styles and finally one more for testing because you are cool. After all of this, you still have to connect these files and write enough code to make them run. You do this every time... every time.

Boring task

I am assuming a lot, but if this is actually you I have good news!
What if I told you there is way to automate this boring and tedious process?
Trust me, these next 10 minutes are going to change your life. Let me introduce you to plop.js.

What is Plop.js?

In their own words, it's a tool that saves you time and helps you build new files with consistency.

How does it work?

It's easier than you think, otherwise I wouldn't be writing about it lol. You create file templates and configure a very simple cli.

Let's start

First, let's clone this simple react app, it has nothing but just a basic react setup.

git clone git@github.com:ivanms1/parcel-template.git
Enter fullscreen mode Exit fullscreen mode

And navigate to it

cd parcel-template
Enter fullscreen mode Exit fullscreen mode

Now let's install plop, on the terminal type:

yarn add plop
# or
npm install plop
Enter fullscreen mode Exit fullscreen mode

The Generator

Next, on the root folder, create a file called plopfile.js and add the following content inside.

module.exports = function (plop) {
  plop.setGenerator("component", {
    description: "Create a component",
    prompts: [
      {
        type: "input",
        name: "name",
        message: "What is this component's name?",
      },
      {
        type: "input",
        name: "element",
        message: "HTML element (div is default)",
        default: "div",
      },
    ],
    actions: [
      {
        type: "add",
        path: "src/components/{{pascalCase name}}/{{pascalCase name}}.tsx",
        templateFile: "templates/Component.tsx.hbs",
      },
    ],
  });
};

Enter fullscreen mode Exit fullscreen mode

We are basically configuring a cli to generate our files. plop.setGenerator creates a generator, the first argument is the name of this generator and the second one is an object with some options where we can configure what to generate. Let's analyze the ones we will be using for this guide.

description

Pretty self explanatory, a description of your generator, for example: Generator of react components.

prompts

Series of steps, questions or instructions we give to the user in order to obtain certain information. Plop stores these in variables to use later in the template files.
In our case we are using input type prompts to get

  • The component's name.
  • The component's html tag (div, button, a, etc), it defaults to div.

message is text the user will see and has to interact with, generally a question or an instruction.

actions

After we've gather all the information need we then proceed to the actions, represented in an array. In our case we only have one action that creates a file.

Let's go a bit into more details with the actions, since it's where things actually happen. The add action type creates a file, path is simply the file path where the file is going to be created. The template is sort of skeleton that will be used to create the file. Plop uses handlebars, a templating language that generates HTML and other text formats.

You might have noticed that we haven't created our template file, and yeah... we need to do that.

Creating our first template

On the root folder create a folder called templates, and add a file named Component.tsx.hbs with the following content.

import React from "react";

interface {{pascalCase name}}Props {}

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

export default {{pascalCase name}};
Enter fullscreen mode Exit fullscreen mode

As you could probably tell, we are creating a react typescript file, in handlebars the variables are inside double brackets ({{}}). pascalCase converts the name variable, that we get from the prompts, to pascal case. So anywhere you see {{pascalCase name}}, it will be replaced with the component's name.

So although this is cool, so far we are only creating a new file with some pre-written react code. There are snippet extensions that could do almost the same thing. Let's make this a bit more complete by also adding a style file.

Adding a style file

I am gonna be using stitches, a css-in-js library similar to styled components but with near-zero runtime, but feel free to use whatever you want.

Let's install the library first, on the terminal run:

yarn add @stitches/react
# or
npm install @stitches/react
Enter fullscreen mode Exit fullscreen mode

Since we now want to create a style file as well, we need to add another action to our generator. Update plopfile.js with the following.

    actions: [
      {
        type: "add",
        path: "src/components/{{pascalCase name}}/{{pascalCase name}}.tsx",
        templateFile: "templates/Component.tsx.hbs",
      },
      // new action here
      {
        type: "add",
        path: "src/components/{{pascalCase name}}/styles.ts",
        templateFile: "templates/styles.ts.hbs",
      },
    ],
Enter fullscreen mode Exit fullscreen mode

Pretty similar to the first action, now we need to add a new template. Inside the templates folder create a file called styles.ts.hbs and add the following content.

import { styled } from '@stitches/react';

export const Styled{{pascalCase name}} = styled('{{element}}', {});
Enter fullscreen mode Exit fullscreen mode

Just your basic css-in-js file, we create a styled component and export it.

Component.tsx.hbs needs to be updated, so it imports and uses the new styled component we made. Now it should look like this:

import React from "react";

import { Styled{{pascalCase name}} } from "./styles";

interface {{pascalCase name}}Props {}

const {{pascalCase name}} = ({} : {{pascalCase name}}Props) => {
  return <Styled{{pascalCase name}}>{{pascalCase name}}</Styled{{pascalCase name}}>;
};

export default {{pascalCase name}};
Enter fullscreen mode Exit fullscreen mode

Now we are talking, plop is saving us some considerable time, generating not one, but two files.

The final step to see this in action is to add the following script to the package.json.

  "scripts": {
    ..., // rest of scripts
    // add this at the end
    "generate": "plop"
  },
Enter fullscreen mode Exit fullscreen mode

We are finally ready, sit down, relax and enjoy the show. On the terminal type

yarn generate
# or
npm run generate
Enter fullscreen mode Exit fullscreen mode

Now let's create a Button component.

Give component a name

With a button tag of course.

Give component a tag

If everything went well

Success

Let's check the components folder.

import React from "react";

import { StyledButton } from "./styles";

interface ButtonProps {}

const Button = ({} : ButtonProps) => {
  return <StyledButton>Button</StyledButton>;
};

export default Button;
Enter fullscreen mode Exit fullscreen mode

The styles file is there as well.

import { styled } from '@stitches/react';

export const StyledButton = styled('button', {});
Enter fullscreen mode Exit fullscreen mode

Cat surprised

Pretty cool eh?

Ok maybe is not that cool, but hopefully by now you've realized the potential this has.

I've kept this simple and only created two files but you can keep playing with it and add as many generators and actions as you want. All people/teams are different and you can tweak plop to whatever convention/style you may have. You can even update existing files if for example you like having an index file for all your components. You can create generators for hooks, pages, helpers, etc, the sky is the limit.

I hope you liked this guide and let me know if you made any cool generators at @ivanms1

Thank you for taking the time to read this article, if you enjoyed it please like to support and follow for more.

Source Code

Top comments (13)

Collapse
 
amirsohel007 profile image
Amir Sohel

this is great ! can we add import same route in router file also?

Collapse
 
ivanms1 profile image
Ivan

Yeah you can append code to existing file with append action. Something like this

      {
        // Action type 'append' injects a template into an existing file
        type: 'append',
        path: 'src/routes/index.js',
        // Pattern tells plop where in the file to inject the template
        pattern: `/* PLOP_INJECT_IMPORT */`,
        template: `import {{pascalCase name}} from './{{pascalCase name}}';`,
      },
Enter fullscreen mode Exit fullscreen mode
Collapse
 
amirsohel007 profile image
Amir Sohel

but also we need to create router :(

Thread Thread
 
amirsohel007 profile image
Amir Sohel

your linkedin? how can we connect

Thread Thread
 
ivanms1 profile image
Ivan

yeah, let's talk on twitter

Collapse
 
tarasg profile image
Taras Gordienko • Edited on

Great! How can I add a dynamic path for files instead of the default src/components/?

Collapse
 
ivanms1 profile image
Ivan • Edited on

Thank you!
You can change the path of the action to whatever you want, for example

path: "src/routes/{{pascalCase name}}/.tsx",
Enter fullscreen mode Exit fullscreen mode

or a dynamic value from the prompts

path: "{{path}}/{{pascalCase name}}/.tsx",
Enter fullscreen mode Exit fullscreen mode
Collapse
 
kepobangetmyid profile image
Kepobanget

Thanks

Collapse
 
ivanms1 profile image
Ivan

You're welcome!

Collapse
 
rohil_cris profile image
Rohil

Great article ivan.

Collapse
 
ivanms1 profile image
Ivan

Thanks Rohil!

Classic DEV Post:

caching

Web Caching Explained by Buying Milk at the Supermarket