Если вы делаете Ctrl+C
каждый раз при создании нового компонента в реакте, то эта статья точно для вас!
У реакта нет своего CLI, и понятно почему. Не существует определенных правил, как именно должна выглядеть структура компонента, есть только общие рекомендации в документации. Все разработчики используют структуру, которая прижилась в их команде. А иногда и вовсе приходится поддерживать проекты в разных стилях.
Сама структура также зависит и от используемого стека:
- Стили — styled, scss modules, css;
- TypeScript или JavaScript;
- Тесты
Существует несколько способов облегчить себе жизнь при создании новых компонентов. Например, можно создать шаблоны в вашей среде разработки (например в WebStorm). Но сегодня мы рассмотрим как создавать полную структуру компонента из командной строки. В конце статьи мы сможем создавать компоненты при помощи одной команды. Например, такой как:
npm run create components/Home/ComponentName
Подготовка
Для создания проекта будем использовать Create React App
Создаем проект:
npx create-react-app react-cli
Весь наш код будет хранится в одном файле. Создаем в папку cli в корне нашего проекта, а внутри нее файл create.js.
Для работы нам понадобятся 3 модуля, импортируем их в наш файл.
// cli/create.js const fs = require('fs'); const path = require('path'); const minimist = require('minimist');
fs — модуль для работы с файловой системой.
path — модуль для обработки путей к файлам.
minimist — модуль для преобразования аргументов из командной строки.
Работа с аргументами
Для того чтобы создать компонент нам нужно передать в командрую строку путь и имя компонента. Мы передадим эту информацию в одной строке (например components/folder1/folder2/Menu
), которую потом распарсим на путь и название.
Все аргументы можно достать из объекта process
. Допустим, мы ввели в консоль следующую строку:
node cli/create.js --path components/folder/Menu
В результате получим:
console.log(process.argv); // [ // '/usr/local/bin/node', // '/Users/a17105765/projects/react-cli/cli/create.js', // '--path', // 'components/folder/Menu' // ]
Используя модуль minimist, мы можем преобразовать аргументы в объект:
// cli/create.js // ... const args = minimist(process.argv); console.log(args); // { // _: [ // '/usr/local/bin/node', // '/Users/a17105765/projects/react-cli/cli/create.js' // ], // path: 'components/folder/Menu' // }
Замечательно, с этим уже можно работать.
Создание директорий
Для начала подготовим необходимые переменные. Нам нужен полный путь до папки src нашего проекта, путь из аргументов в виде массива и название компонента.
// cli/create.js // ... // достаем путь до папки src текущего проекта const srcPath = [__dirname, '..', 'src']; // разбиваем путь из аргумента командной строки на массив const arrPath = args.path.split('/'); // достаем последний элемент массива (название компонента) const componentName = arrPath[arrPath.length - 1];
Допустим, мы указали несуществующий путь. По-хорошему, мы должны создать все эти вложенные папки, если их нет. Так и сделаем.
// cli/create.js // ... // создание директорий из аргумента (при необходимости) const currentArray = []; arrPath.forEach(element => { currentArray.push(element); const currentResolvePath = path.resolve(...srcPath, ...currentArray); if (!fs.existsSync(currentResolvePath)) { // проверка - существует такая директория или нет? fs.mkdirSync(currentResolvePath); // если нет, то создаем новую } });
Здесь мы циклом проходимся по всем элементам пути и при необходимости создаем директорию с помощью метода mkdirSync
. До этого нормализуем путь к компоненту в одну строку с помощью метода resolve
. После выполнения данных операций у нас будет создана необходимая структура директорий.
Протестируем написанное. Вводим в командную строку следующую команду (при этом у нас пока нет никаких директорий в папке src
):
node cli/create.js --path components/A/B/C/D/E/CustomComponent
И мы получим следующий результат:
Создание файлов компонента
Отлично, пол дела сделано, осталось создать файлы компонента.
Мы будем использовать самую простую структуру компонента:
- Для стилей обычный css
- Без TS
- Без тестов
- Функциональный компонент
Получается, нам нужно создать 3 файла.
1. Шаблон компонента
import React from 'react'; import './CustomComponent.css'; const CustomComponent = () => { return ( <div className="wrapper"> </div> ); }; export default CustomComponent;
2. Шаблон индексного файла
export { default } from './CustomComponent';
3. Шаблон файла стилей
.wrapper {}
Для начала достанем в одну переменную полный путь до компонента (включая личную папку компонента):
// cli/create.js // ... const componentPath = [...srcPath, ...arrPath];
Новые файлы создаются при помощи команды writeFileSync
, которая принимает путь до файла и содержимое.
Создание файла компонента:
// cli/create.js // ... const componentCode = `import React from 'react'; import './${componentName}.css'; const ${componentName} = () => { return ( <div className="wrapper"> </div> ); }; export default ${componentName};`; fs.writeFileSync(path.resolve(...componentPath, `${componentName}.jsx`), componentCode);
Создание индексного файла:
// cli/create.js // ... const indexCode = `export { default } from './${componentName}';`; fs.writeFileSync(path.resolve(...componentPath, 'index.js'), indexCode);
Создание файла стилей:
// cli/create.js // ... const styleCode = '.wrapper {}'; fs.writeFileSync(path.resolve(...componentPath, `${componentName}.css`), styleCode);
Готово!
Теперь посмотрим что у нас получилось.
// cli/create.js const fs = require('fs'); // модуль для работы с файловой системой const path = require('path'); // модуль для преобразования пути const minimist = require('minimist'); // модуль для преобразования строки аргументов в объект const args = minimist(process.argv); const srcPath = [__dirname, '..', 'src']; // путь до папки src текущего проекта const arrPath = args.path.split('/'); // разбиваем путь из аргумента командной строки на массив const componentName = arrPath[arrPath.length - 1]; // последний элемент - название компонента // создание директорий из аргумента (при необходимости) const currentArray = []; arrPath.forEach(element => { currentArray.push(element); const currentResolvePath = path.resolve(...srcPath, ...currentArray); if (!fs.existsSync(currentResolvePath)) { // проверка - существует такая директория или нет? fs.mkdirSync(currentResolvePath); // если нет, то создаем новую } }); const componentPath = [...srcPath, ...arrPath]; // создание компонента const componentCode = `import React from 'react'; import './${componentName}.css'; const ${componentName} = () => { return ( <div className="wrapper"> </div> ); }; export default ${componentName};`; fs.writeFileSync(path.resolve(...componentPath, `${componentName}.jsx`), componentCode); // создание индексного файла const indexCode = `export { default } from './${componentName}';`; fs.writeFileSync(path.resolve(...componentPath, 'index.js'), indexCode); // создание файла стилей const styleCode = '.wrapper {}'; fs.writeFileSync(path.resolve(...componentPath, `${componentName}.css`), styleCode);
Получилось всего 43 строки с учетом комментариев, неплохо для такой полезной штуки!
Теперь попробуем создать компонент:
node cli/create.js --path components/folder1/folder2/Button
Все получилось! Остался последний штрих…
Добавление команды в package.json
Добавим команду в файл package.json, чтобы каждый раз не писать путь к скрипту
{ "name": "react-cli", "version": "0.1.0", "private": true, "dependencies": { "react": "^16.12.0", "react-dom": "^16.12.0", "react-scripts": "3.2.0" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "create": "node cli/create.js --path" }, "eslintConfig": { "extends": "react-app" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } }
Теперь вместо:
node cli/create.js --path components/folder1/folder2/Button
можем просто написать
npm run create components/folder1/folder2/Button
ссылка на оригинал статьи https://habr.com/ru/post/477780/
Добавить комментарий