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
2. Styled Component
3. Storybook
4. index.js
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
.
It prompts a question with two options component
or page
If you choose component
. Then,
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.
If you were chosen page
instead of component
, then the resulting will be:
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!
Top comments (1)
Nice and helpful post @abdulkareemtpm . Good luck!