De igual forma, hemos definido una arquitectura base junto a nuestro equipo que solicitamos mantener y que a veces no es fácil de hacerlo.
Para ello, podemos utilizar una herramienta pequeña, pero poderosa, llamada Plop.
Plop es (…) un “micro-generator framework”. Ahora, lo llamo así porque es una pequeña herramienta que le brinda una forma simple de generar código o cualquier otro tipo de archivos de texto plano de forma consistente. Vemos, todos creamos estructuras y patrones en nuestro código (rutas, controladores, componentes, ayudantes, etc.). Estos patrones cambian y mejoran con el tiempo, por lo que cuando necesita crear un NUEVO patrón, no siempre es fácil encontrar los archivos en su base de código que representan la “mejor práctica” actual. Es ahí donde plop lo salva.
#.Iniciando con Plop
Para comenzar, vamos a crear un proyecto simple e instalar Plop como una dependencia de desarrollo en nuestro proyecto.
mkdir test-plop
cd test-plop
npm init -y
npm install plop --save-dev
Con esto, ya tenemos plop instalado en nuestro proyecto y podemos comenzar a utilizarlo. Para ello, vamos a crear un archivo llamado plopfile.js
en la raíz de nuestro proyecto.
module.exports = function (plop) {
plop.setGenerator('basics', {
description: 'this is a skeleton plopfile',
prompts: [],
actions: []
});
};
También agregaremos un script en nuestro package.json
para ejecutar plop:
// ...
{
"scripts": {
"plop": "plop"
}
}
// ...
Y lo ejecutamos solo para asegurarnos que todo está funcionando como debería:
npm run plop
plop-test@1.0.0 plop
plop
#.Generando el primer generador: un componente de React
Digamos que nuestro equipo ha decidido utilizar React y ha definido una arquitectura base para nuestros componentes. En este caso, vamos a crear un generador que nos permita crear un componente de React con la siguiente estructura:
- Utilizará la extensión
.jsx
. - Utilizará
PropTypes
para la definición de tipos. - Tendrá un nombre en PascalCase.
- Tendrá un directorio con el mismo nombre.
- Tendrá un archivo
index.jsx
que exportará el componente. - Tendrá un archivo
[ComponentName].copy.json
que contendrá el texto plano que utiliza el componente. - Tendrá un archivo
[ComponentName].module.scss
que exportará los estilos del componente.
Para ello, vamos a modificar nuestro archivo plopfile.js
y agregaremos el nombre de nuestro generador, una descripción y las preguntas que queremos hacerle al usuario para la generación de nuestros componentes.
module.exports = function (plop) {
plop.setGenerator('component', {
description: 'Create a new component',
prompts: [
{
type: 'input',
name: 'name',
message: 'What is your component name?',
},
],
actions: [
{
type: 'add',
path: 'src/components/{{pascalCase name}}/index.jsx',
templateFile: 'plop-templates/component/index.jsx.hbs',
},
{
type: 'add',
path: 'src/components/{{pascalCase name}}/{{pascalCase name}}.copy.json',
templateFile: 'plop-templates/component/copy.js.hbs',
},
{
type: 'add',
path: 'src/components/{{pascalCase name}}/{{pascalCase name}}.module.scss',
templateFile: 'plop-templates/component/component.module.scss.hbs',
},
],
});
};
Vemos que estamos haciendo referencia a un directorio llamado plop-templates
que aún no existe. Este directorio contendrá los archivos que utilizaremos como plantillas para la generación de nuestros componentes. Para ello, vamos a crearlo y agregar los archivos que utilizaremos como plantillas. También crearemos el directorio src/components
que contendrá nuestros componentes.
mkdir plop-templates
mkdir src
mkdir src/components
Y creamos nuestros templates o plantillas para la generación de nuestras 3 plantillas. Estas plantillas se escriben en Handlebars.
// plop-templates/component/index.jsx.hbs
import React from 'react';
import PropTypes from 'prop-types';
import COPY from './{{pascalCase name}}.copy.json';
import styles from './{{pascalCase name}}.module.scss';
const {{pascalCase name}} = () => {
return (
<div className={styles.container}>
<h1>{COPY.title}</h1>
</div>
);
};
{{pascalCase name}}.propTypes = {
// property: PropTypes.string.isRequired
};
export default {{pascalCase name}};
// plop-templates/component/copy.js.hbs
{
"title": "{{pascalCase name}} title"
}
// plop-templates/component/component.module.scss.hbs
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
Con esto, podemos proceder a ejecutar nuestro generador y ver el resultado.
npm run plop
> plop-test@1.0.0 plop
> plop
? What is your component name? Test
✔ ++ /src/components/Test/index.jsx
✔ ++ /src/components/Test/Test.copy.json
✔ ++ /src/components/Test/Test.module.scss
Y si exploramos el archivo generado, veremos que el name
que ingresamos en la consola se ha utilizado en la generación de nuestros archivos, y utilizando PascalCase
.
// src/components/Test/index.jsx
import React from 'react';
import PropTypes from 'prop-types';
import COPY from './Test.copy.json';
import styles from './Test.module.scss';
const Test = () => {
return (
<div className={styles.container}>
<h1>{COPY.title}</h1>
</div>
);
};
Test.propTypes = {
// property: PropTypes.string.isRequired
};
export default Test;
#.Próximos pasos
Con Plop podemos generar cualquier tipo de archivo, desde componentes de React hasta archivos de configuración, stories
o hasta tests
.
Igualmente, Plop permite la creación de prompts personalizados, los que por debajo utilizan Inquirer.js. Esto nos permite crear preguntas que nos permitan generar archivos de acuerdo a las respuestas que el usuario ingrese o incluso un flujo de preguntas, validaciones, etc.
Por ejemplo, si quisieramos agregar una validación para que el nombre del componente contenta al menos 3 caracteres, podríamos hacerlo de la siguiente manera y agregaríamos el siguiente prompt, llamado name
:
const name = {
type: 'input',
name: 'name',
message: 'What is your component name?',
validate: (input) => {
if (input.length >= 3) {
return true;
}
return 'name should be at east 3 characters long.';
},
};
module.exports = function (plop) {
plop.setGenerator("components", {
description: "generate a component",
prompts: [name],
// ... el resto quedaría igual
y al ejecutarlo, podemos ver la nueva validación:
npm run plop
> plop-test@1.0.0 plop
> plop
? What is your component name? a
>> name should be at east 3 characters long.
El resto, funcionaría exactamente igual, solo que agregamos una capa nueva para la validación. De ahí en adelante, el cielo es el límite 🌁🙌.