Создание генератора компонентов React

В этом посте присоединяйтесь ко мне, поскольку я создаю генератор для компонента React. Мы будем использовать действительно классный инструмент под названием Plop, и в итоге мы сможем создавать новые компоненты быстрее и лучше.

Введение

Если вы цените хороший опыт разработчиков (DX) и стремитесь поддерживать хорошее качество/стандарты кодирования, то наличие инструмента для генерации кода в виде лесов компонентов просто необходимо. Независимо от того, поддерживаете ли вы библиотеку компонентов в своей организации, такой инструмент позволит вам и вашим коллегам увеличить скорость разработки и сосредоточиться на действительно важных аспектах разработки компонентов.

Требования
Итак, чего же мы хотим добиться?
Ну, наш генератор должен создать следующее:

  • Папка Component с именем, заданным разработчиком
  • Файл index.jsx для компонента
  • Файл index.css, который файл index.jsx будет импортировать с основными общими правилами
  • Файл index.test.js с одним тестом, который проверяет рендеринг компонента
  • Файл Storybook, содержащий одну историю для компонента.

Это довольно много. Давайте приступим к этому


Plop

Как уже упоминалось выше, одним из инструментов, который может помочь нам сгенерировать такой код, является Plop. Я нахожу этот инструмент очень интуитивным и с довольно понятной документацией.

Следуя документации по Plop, давайте сначала установим его и убедимся, что мы можем его использовать:

yarn add plop -D

Это, конечно, зависимость от dev.

Давайте создадим наш файл plopfile.js прямо из примера, используя формат CJS, поскольку проект, для которого я это делаю, в настоящее время не поддерживает формат ESM:

module.exports = function (plop) {
   // create your generators here
   plop.setGenerator('basics', {
       description: 'this is a skeleton plopfile',
       prompts: [], // array of inquirer prompts
       actions: [], // array of actions
   });
};
Вход в полноэкранный режим Выход из полноэкранного режима

Прежде чем мы зальем больше контента в этот генератор, давайте проверим, запускается ли Plop как ожидалось, добавив npm-скрипт в наш package.json и вызвав его:

"scripts": {
       . . .
       "plop": "plop"
   },
Войти в полноэкранный режим Выход из полноэкранного режима

Запускаем yarn plop и… ничего не происходит. Нам нужно ввести генератор. Я возвращаюсь к своему plopfile.js и добавляю это:

plop.setGenerator('React component generator', {
       description: 'A generator for React components',
       prompts: [
           {
               type: 'input',
               name: 'name',
               message: 'Component name',
           },
       ],
   });
Войти в полноэкранный режим Выйти из полноэкранного режима

Запускаю plop снова и получаю приятную подсказку с запросом имени компонента. Я дал ему имя “Matti”, но получил эту ошибку:

True. Давайте добавим действие.
В нашем действии я хотел бы создать директорию по имени заданного компонента и поместить в нее пустой файл index.jsx (пока). Теперь мой генератор выглядит следующим образом:

plop.setGenerator('React component generator', {
       description: 'A generator for React components',
       prompts: [
           {
               type: 'input',
               name: 'name',
               message: 'Component name',
           },
       ],
       actions: [
           {
               type: 'add',
               path: 'src/{{name}}/index.jsx',
           },
       ],
   });
Вход в полноэкранный режим Выход из полноэкранного режима

Очень интуитивно понятно IMO.
Итак, теперь у меня есть файл index.jsx, расположенный в каталоге Matti, который находится в каталоге src. Отлично.

Давайте заполним содержимое этого файла. Для этого мы будем использовать шаблон Handlebars (да, .hbs файл, вы не ослышались), который позволит нам создать содержимое в соответствии с именем компонента, которое мы задали ранее – …

Я создаю plop-templates/react-component/index.hbs в корне проекта и помещаю туда минимальный код, необходимый для создания React-компонента:

import React from 'react';
import PropTypes from 'prop-types';

const MyComponent = (props)=> {
   return <div>MyComponent {props.sampleProp}</div>
}

MyComponent.propTypes = {
   sampleProp: PropTypes.number,
};

export default MyComponent;
Вход в полноэкранный режим Выход из полноэкранного режима

Обратите внимание, что я пока не использую никаких динамических полей в этом шаблоне.
Теперь я скажу ранее сделанному действию использовать этот шаблон при создании компонента:

actions: [
           {
               type: 'add',
               path: 'src/{{name}}/index.jsx',
               templateFile: 'plop-templates/react-component/index.hbs',
           },
       ],
Войти в полноэкранный режим Выйти из полноэкранного режима

Давайте запустим Plop и посмотрим, что мы получим.
Да, файл создается с ожидаемым содержимым (BTW, если файл уже существует, он предупредит об этом и не будет его переопределять).
Пришло время использовать данное имя компонента внутри шаблона:

import React from 'react';
import PropTypes from 'prop-types';

const {{name}} = (props)=> {
   return <div>{{name}} {props.sampleProp}</div>
}

{{name}}.propTypes = {
   sampleProp: PropTypes.number,
};

export default {{name}};
Войти в полноэкранный режим Выход из полноэкранного режима

Намного лучше! После генерации компонента теперь файл index.jsx установлен правильно.

Быстро проверяем, что мы имеем на данный момент – папку Component с именем, заданным разработчиком, и файл index.jsx для компонента. Отлично, переходим к созданию файла index.css для этого компонента.

Я бы хотел, чтобы файл index.css содержал имя класса в соответствии с именем данного компонента, но в нижнем регистре, и для этого было бы неплохо ввести вспомогательную функцию, которую Handlebars сможет использовать.
В plopfile.js я добавляю следующее:

// Helpers
   plop.setHelper('toLowerCase', function (text) {
       return text.toLowerCase();
   });
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь я создам шаблон index.css в plop-templates/react-component/index.css.hbs со следующим содержанием:

.{{toLowerCase name}} {
   color: aqua;
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Имея шаблон .css, я хотел бы, чтобы plop action генерировал его вместе с файлом index.jsx. Как мне это сделать?

Для этого нам потребуется использовать другой api Plop под названием “addMany” и немного изменить имена шаблона index.jsx. Давайте начнем с изменения имени шаблона, и вы скоро поймете почему –

index.hbs переименован в index.jsx.hbs.

Переходя к plopfile, давайте используем действие “addMany” следующим образом:

actions: [
           {
               type: 'addMany',
               destination: 'src/{{name}}',
               base: `plop-templates/react-component/`,
               templateFiles: 'plop-templates/react-component/*',
           },
       ],
Вход в полноэкранный режим Выйти из полноэкранного режима

Вам может быть интересно, что здесь происходит (и в документации это не совсем ясно).
Пункт назначения” – это место, где мы хотим сгенерировать все наши файлы.
“templateFiles” (обратите внимание на маленькую “s” в конце) – это место, где находятся все шаблоны для данного действия. Там хорошо было бы создать директорию для каждого генератора.
Base” – это часть, которую мы хотели бы удалить из имен конечных файлов.

Plop знает, что нужно удалить “.hbs” и “base” из конечного имени файла, и именно поэтому мы изменили имя индексного файла.

Давайте сделаем небольшие изменения в шаблоне index.js.hbs, чтобы наш компонент импортировал и использовал сгенерированный для него index.css:

import React from 'react';
import PropTypes from 'prop-types';
import './index.css';

const {{name}} = (props)=> {
   return <div className="{{toLowerCase name}}">{{name}} {props.sampleProp}</div>
}

{{name}}.propTypes = {
   sampleProp: PropTypes.number,
};

export default {{name}};
Вход в полноэкранный режим Выход из полноэкранного режима

Потрясающе! У нас есть сгенерированный css файл, который компонент импортирует и использует. Переходим к тестовому файлу.
Мы хотим создать тестовый файл Jest, который будет тестировать минимальный рендеринг компонента.

Начнем с создания шаблона index.test.hbs в том же месте, где и остальные шаблоны:

import React from 'react';
import {render, screen} from '@testing-library/react';
import {{name}} from '.';

describe('{{name}} component', () => {
   it('should render', () => {
       const mockSampleProp = 5;
       const textQuery = `{{name}} ${mockSampleProp}`

       render(<{{name}} sampleProp={mockSampleProp}/>);

       expect(screen.getByText(textQuery)).toBeInTheDocument();
   });
});
Вход в полноэкранный режим Выход из полноэкранного режима

Нам не нужно ничего менять в нашем plopfile. Этот шаблон будет обнаружен, и будет сгенерирован тестовый файл.
Запускаем Jest, чтобы убедиться, что все прошло, и действительно – у нас есть успех 🙂

Переходим к истории Storybook, ну… вы поняли ее суть. Я создаю шаблон под названием index.stories.jsx.hbs со следующим содержанием:

import React from 'react';
import {{name}} from './index.jsx';

// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default {
 title: 'Components/{{name}}',
 component: {{name}},
 // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
 argTypes: {},
};

// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const Template = (args) => <div><{{name}} {...args} /></div>;

export const Simple = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args
Simple.args = {
   sampleProp:5,
};
Вход в полноэкранный режим Выйти из полноэкранного режима

Запускаю plop снова и файл истории создается и отображается на Story book –

Какой замечательный компонент!

И это, друзья мои, все 🙂

Подведем итоги…

Теперь у нас есть генератор компонентов React, который создает для нас 4 файла с заданным именем компонента. Теперь любой разработчик может создать компонент и начать работу за считанные секунды.
Помимо ускорения процесса создания компонентов и обеспечения лучшего DX, это помогает выровнять стандарты компонентов в большой организации.
Код можно найти на моем монорепозитории Pedalboard.

Как всегда, если у вас есть вопросы или предложения о том, как это можно сделать лучше, обязательно оставьте их в комментариях ниже 🙂

Эй! Если вам понравилось то, что вы только что прочитали, проверьте @mattibarzeev на Twitter 🍻

Photo by KOBU Agency on Unsplash

Оцените статью
Procodings.ru
Добавить комментарий