Всем привет!


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


Example


Зачем все это?


Ни раз, говоря об этом CLI другим разработчикам, я встречал вопросы, вызванные непониманием того зачем понадобилось писать свой пакет. Ведь во всех современных редакторах есть шаблоны для файлов и этот процесс более или менее можно автоматизировать. И в этом есть логика. Но она хорошо работает, когда у вас небольшой проект и вы единственный человек который им занимается.


Я пришел к решению создать свой пакет, когда я оказался в проекте, в котором все работали в моно-репозиторий с 12-ю разными проектами, но при этом, пытающимися выдерживать какую-то общую структуру.


Более того, в репозитории есть сразу и бэкенд и фронтенд, а значит все лежит далеко не в самом корне репозитория и чтобы дойти до нужной папки, нужно прилично закопаться.


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


Но есть и еще один, не менее важный нюанс, который я пытался решить с помощью CLI. Когда вы работаете над большим проектом вы вынуждены использовать линтеры и другие инструменты ограничения свободы разработчиков, но чаще всего, эти инструменты никак не описывают структуру приложения, то каким должен быть компонент, каким принято его делать в данный момент в данной команде. Очень часто попадая в большой проект, довольно просто найти несколько архитектурных решений к построению компонента и без помощи других разработчиков невозможно разобраться как делать правильно и под что настроить свой IDE.
Кроме того, все эти шаблоны довольно сложно шарятся между разработчиками и нет возможности их централизовано актуализировать. Более того, если так оказывается, что вы сразу работаете над несколькими проектами, довольно проблематично держать в голове где какие правила приняты.


Что мы хотим?


Исходя из вышеперечисленных проблем, в первом приблежении я хотел, чтобы CLI предоставлял следующие возможности:


  1. Возможность указать путь до папки или папок с компонентами любой вложенности
  2. Возможность удобного выбора места для размещения нового компонента в проекте с учетом вложенности
  3. Возможность работать сразу с несколькими проектами в едином формате из корня репозитория
  4. Возможность указания ссылок на файлы для организации импортов и экспортов
  5. Возможность указать любые форматы файлов для стилей (css, scss, less) и для скриптов (ts, tsx, js, jsx)

В наших проектах компонент имел следующую структуру:


  • ComponentName
    — index.ts (Реэкспорт компонента)
    — ComponentName.tsx (Здесь нужно импортировать стили)
    — ComponentName.module.scss
    — ComponentName.test.tsx (Здесь нужен импорт компонента)
    — ComponentName.stories.tsx (Здесь нужен импорт компонента)

И вы можете представить себе, как "удобно" создавать компонент с такой структурой каждый раз, стараясь нигде не описаться, и не забыть поменять название во всех местах, если вдруг кто-то решил скопировать компонент.


Спойлер: Хотелки на этом не закончились и список возможностей расширился до такой степени что привязка пакета к React носит достаточно условный характер, поскольку при желании её можно настроить на генерацию компонент и для React Native и для каких-то контроллеров в BFF и чего угодно еще, имеющего подобный, компонентный подход.

Как будем решать проблему?


Вопрос генерации файлов и шаблонизации решился просто, я не стал изобретать ничего сверх сложного и на стандартном fs и регулярках сдедал шаблоны для компонента. Самое же интересное — это было дать возможность пользователю легко выбирать нужные настройки, не заставляя его печатать кучу флагов, как это сделано во многих существующих CLI. И так как я старался получить хороший UX, то я начал искать подходящее решение для интерактивного создания компонента и как основу для своего CLI я удачно нашел библиотеку prompts. Изначально я её планировал использовать как метод настройки компонента и ввода имени, но потом идея использовать зацикленный селект для выбора папки показалась очень симпатичной и оказалась неверноятно удобной. Потом я и вовсе заменил его на автокомплит, благодаря которому удалось сделать удобный поиск по папкам, благодаря чему выбирать путь стало не сложнее чем через автокомплит в Linux, причем на любой вложенности у папки с компонентами.


Так как все равно кто-то захочет воспользоваться теми же фичами просто вызвав нужную команду, я также добавил библиотеку commander в проект и добавил пробрасывание всех основных опций в обход интерактивного выбора.


Можно ли сделать еще лучше?


Благодаря хорошей комбинации этих библиотек, удалось довольно быстро покрыть те задачи, которые я для себя ставил в MVP, но потом, я подумал что классно было бы иметь возможность генерировать сразу несколько компонент за раз. Показалось крутым дать возможность прицепить какой-то пост-процессинг для файлов. Добавить фичу создания не только компонент, но и чего-то еще. Появилась идея сделать быструю конфигурацию в отдельном режиме передав флаг --init. И благодаря достаточно неплохой архитектуре, которую я изначально заложил в проект, вышло так, что все эти фичи влетали в проект буквально за час-два.


Проект конечно все еще есть куда развивать. Есть идея добавить возможность не только добавлять компоненты, но и докидывать в них то что в них не хватает. Добавили вы, к примеру, в проект Storybook, хотите в уже существующий компонент добавить историю и вместо того чтобы просто использовать шаблон, также как при создании, приходится вновь заниматься ручной работой, что не очень удобно. И эта фича тоже должно довольно легко въехать на существующие рельсы, хочется это только сделать максимально прозрачно для нового пользователя и при этом удобно и быстро для опытного, поэтому я пока думаю над реализацией фичи.


Где можно попробовать?


CLI называется reactcci и доступен в npm и yarn и для того чтобы его попробовать в деле не обязательно что-то настраивать. Под копотом уже есть готовый конфиг который позволяет генерировать компонент с CSS-модулями и тестами, но, если вы захотите что-то подправить — это делается тоже очень просто. Вызываете npx rcci --init, отвечаете на пару вопросов, изменяете шаблоны и конфиг, и тем самым вы можете заставить CLI генерировать все что вам угодно. А если вам что-то не удастся реализовать, можете завести issue на github и я добавлю эту фичу в кротчайшие сроки.