Escrevendo sua própria CLI para React

Se você Ctrl+C toda vez que criar um novo componente na reação, este artigo será para você!



A reação não possui sua própria CLI e é compreensível o porquê. Não há regras específicas para a aparência da estrutura do componente; existem apenas recomendações gerais na documentação. Todos os desenvolvedores usam uma estrutura que criou raízes em sua equipe. E às vezes você precisa apoiar projetos em diferentes estilos.


A estrutura em si também depende da pilha usada:


  • Estilos - estilo, módulos scss, css;
  • TypeScript ou JavaScript;
  • Testes

Existem várias maneiras de facilitar sua vida ao criar novos componentes. Por exemplo, você pode criar modelos em seu ambiente de desenvolvimento (por exemplo, no WebStorm). Hoje, porém, veremos como criar uma estrutura completa de componentes a partir da linha de comando. No final do artigo, poderemos criar componentes com um único comando. Por exemplo, como:


 npm run create components/Home/ComponentName 

Preparação


Usaremos o aplicativo Create React para criar o projeto .


Crie um projeto:


 npx create-react-app react-cli 

Todo o nosso código será armazenado em um arquivo. Criamos a pasta cli na raiz do nosso projeto e, dentro dela, o arquivo create.js.


Para trabalhar, precisamos de 3 módulos, nós os importamos para o nosso arquivo.


 // cli/create.js const fs = require('fs'); const path = require('path'); const minimist = require('minimist'); 

fs - módulo para trabalhar com o sistema de arquivos.


path - módulo para processar caminhos de arquivo.


minimist - um módulo para converter argumentos da linha de comando.


Trabalhar com argumentos


Para criar um componente, precisamos passar o caminho e o nome do componente para a linha de comando. Transferiremos essas informações em uma linha ( por exemplo, components/folder1/folder2/Menu ), que depois analisamos para o caminho e o nome.


Todos os argumentos podem ser recuperados do objeto de process . Suponha que inserimos a seguinte linha no console:


 node cli/create.js --path components/folder/Menu 

Como resultado, obtemos:


 console.log(process.argv); // [ // '/usr/local/bin/node', // '/Users/a17105765/projects/react-cli/cli/create.js', // '--path', // 'components/folder/Menu' // ] 

Usando o módulo minimist, podemos converter os argumentos em um objeto:


 // 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' // } 

Ótimo, você já pode trabalhar com isso.


Criando diretórios


Primeiro, prepare as variáveis ​​necessárias. Precisamos do caminho completo para a pasta src do nosso projeto, o caminho dos argumentos como uma matriz e o nome do componente.


 // cli/create.js // ... //     src   const srcPath = [__dirname, '..', 'src']; //         const arrPath = args.path.split('/'); //     ( ) const componentName = arrPath[arrPath.length - 1]; 

Suponha que tenhamos indicado um caminho inexistente. De uma maneira boa, precisamos criar todas essas subpastas se elas não estiverem lá. Então vamos lá.


 // cli/create.js // ... //     ( ) const currentArray = []; arrPath.forEach(element => { currentArray.push(element); const currentResolvePath = path.resolve(...srcPath, ...currentArray); if (!fs.existsSync(currentResolvePath)) { //  -     ? fs.mkdirSync(currentResolvePath); //  ,    } }); 

Aqui, percorremos todos os elementos do caminho e, se necessário, criamos um diretório usando o método mkdirSync . Antes disso, normalizamos o caminho para o componente em uma linha usando o método resolve . Após executar essas operações, criaremos a estrutura de diretórios necessária.


Teste escrito. Nós inserimos o seguinte comando na linha de comando (ao mesmo tempo, ainda não temos nenhum diretório na pasta src ):


 node cli/create.js --path components/A/B/C/D/E/CustomComponent 

E obtemos o seguinte resultado:



Criando arquivos de componentes


Bem feito, tudo o que resta é criar os arquivos componentes.


Usaremos a estrutura de componentes mais simples:


  • Para estilos css simples
  • Sem TS
  • Sem testes
  • Componente funcional

Acontece que precisamos criar 3 arquivos.


1. Modelo de componente


 import React from 'react'; import './CustomComponent.css'; const CustomComponent = () => { return ( <div className="wrapper"> </div> ); }; export default CustomComponent; 

2. Modelo de arquivo de índice


 export { default } from './CustomComponent'; 

3. Modelo de arquivo de estilo


 .wrapper {} 

Para começar, vamos obter o caminho completo para o componente (incluindo a pasta pessoal do componente) em uma variável:


 // cli/create.js // ... const componentPath = [...srcPath, ...arrPath]; 

Novos arquivos são criados usando o writeFileSync , que pega o caminho e o conteúdo do arquivo.


Criando um arquivo de componente:


 // 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); 

Criando um arquivo de índice:


 // cli/create.js // ... const indexCode = `export { default } from './${componentName}';`; fs.writeFileSync(path.resolve(...componentPath, 'index.js'), indexCode); 

Criando uma folha de estilo:


 // cli/create.js // ... const styleCode = '.wrapper {}'; fs.writeFileSync(path.resolve(...componentPath, `${componentName}.css`), styleCode); 

Feito!


Agora vamos ver o que aconteceu.


 // 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); 

Foram apenas 43 linhas, levando em consideração os comentários, nada mal para uma coisa tão útil!


Agora vamos tentar criar um componente:


 node cli/create.js --path components/folder1/folder2/Button 


Tudo deu certo! Há o último toque ...


Adicionando um comando ao package.json


Adicione o comando ao arquivo package.json para que a cada vez que não escrevemos o caminho no script


 { "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" ] } } 

Agora, em vez de:


 node cli/create.js --path components/folder1/folder2/Button 

podemos apenas escrever


 npm run create components/folder1/folder2/Button 

O código fonte do projeto pode ser visualizado no github

Source: https://habr.com/ru/post/pt477780/


All Articles