DEV Community

Cover image for Como criar componentes customizáveis e publicar no npm!
Rafael Costa
Rafael Costa

Posted on • Updated on

Como criar componentes customizáveis e publicar no npm!

Nesse artigo, irei mostrar como criar componentes e como deixa-los customizáveis dependendo do que vier por props. E no final mostrarei como publicar no npm! (para instalar usando o comando npm install --save nome_da_lib) 😁

O meu componente vai ser um botão de loading, exemplo na imagem abaixo:

 

Alt Text

 

Ignore os estilos, leve em conta que é representativo 😂

 

Para iniciar sua lib, utilize o seguinte comando com o npx:

npx create-react-app nome-da-sua-lib

 

Sim, utilizaremos o comando de criar um projeto em React mesmo. No meu caso, como irei criar um button loading, o meu comando é:

npx create-react-app button-loading

 

Feito isso, você pode começar apagando todos os arquivos de dentro de src e deixando apenas o index.js.

Deixei o meu index.js assim:

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <div>
    <h1>Hello World</h1>
  </div>,
  document.getElementById('root')
);

 

O nosso componente irá ficar na pasta lib dentro de src.

Minha pasta lib ficou assim:

Alt Text

 

Dentro de lib/index.js eu exporto meu botão para quando alguém for instalar a lib, importar com import ButtonLoading from '@rafaelsevla/button-loading' e não com import ButtonLoading from '@rafaelsevla/button-loading/Button-Loading'.

 

Depois disso, criei um componente de botão sem estilo e importei na minha index.js de dentro de src/, para ir acompanhando a evolução do componente, e ficou assim:

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';

import ButtonLoading from './lib/ButtonLoading'

ReactDOM.render(
  <div>
    <ButtonLoading />
  </div>,
  document.getElementById('root')
);

 

Componente do botão:

import React from 'react';

const ButtonLoading = () => (
  <button>
    Click in me
  </button>
)

export default ButtonLoading;

 

Agora eu adicionei alguns estilos no botão para ele ter as opções primary e danger. Como o foco do artigo não é estilização e sim como customizar componentes React, vou deixar o link dos estilos aqui.

 

Inclusive, utilizei styled components, caso tenha curiosidade para saber como funciona eu escrevi um artigo um tempo atrás sobre ele aqui.

 

Meu arquivo do botão ficou assim:

import React from 'react';

// importei o arquivo os componentes estilizados
import { Button, Spinner } from './styles.js'

// aqui defino meu dicionário de cores
const colors = {
  primary: '#7001e7',
  danger: '#9c0000'
}

// adicionei três propriedades que o botão pode receber e coloquei em seus devidos lugares
const ButtonLoading = ({ title, color, loading }) => (
  <Button color={colors[color]}>
    {/* aqui eu verifico se mostro o loading ou o texto do botão */}
    {loading
      ? <Spinner />
      : title}
  </Button>
);

// adicionei as propriedades padrão, caso o botão não receba nada
ButtonLoading.defaultProps = {
  title: 'Click in me',
  color: 'primary',
  loading: false
}

export default ButtonLoading;

 

E para usar o botão, basta eu adicionar as props onde estiver meu botão.
Detalhe que no loading eu posso chamar um estado do meu componente (página) que é booleano.

<ButtonLoading
  title='Meu Botão'
  color='danger'
  loading={meuEstadoBooleano}
/>

 

Dessa forma, o componente já está sendo customizável. Ele já está recebendo props e reagindo da forma que se espera como por exemplo, o loading que inverte com o texto ou o color que pode ser primary ou danger.

 

Caso queira colocar mais cores no botão, só precisaria adicionar mais uma cor secondary no dicionário colors e ela ser toda verde, por exemplo.

 

Mas aí você pode se perguntar: como eu poderia deixar o botão quadrado ~ou redondo ou whatever~ em apenas uma tela mandando estilos por props ao invés de criar um tipo somente pra isso?

Basta colocar o botão para receber a prop styles e chamar no botão:

const ButtonLoading = ({ title, color, loading, styles }) => (
  <Button color={colors[color]} styles={styles}>
    ...
  </Button>
);

ButtonLoading.defaultProps = {
  ...
  styles: {}
}

 

E na chamada ficaria assim:

<ButtonLoading styles={{ backgroundColor: '#f0f', borderRadius: 200, color: '#ff0' }} />

 

Note que eu alterei a cor de fundo e do texto (isso é possível também, caso eu não me satisfaça com o que a lib já tem).


. . .

Uma propriedade que posso receber no meu botão são as cores do spinner, deixaria o branco e azul como default mas com opção de receber outras.

Como eu defino as cores do spinner dentro do styled component Spinner, eu abstraio essas duas cores para utilizar o que vem por props.

export const Spinner = styled.div`
  @keyframes spinner {
    0% { transform: rotate(0deg); }
    50% { transform: rotate(1000deg); }
    100% { transform: rotate(360deg); }
  }

  border: 5px solid #f3f3f3; /* <-- branco */
  border-top: 5px solid #3498db; /* <-- azul */
  border-radius: 50%;
  width: 20px;
  height: 20px;
  animation: spinner 2s linear infinite;
`

 

Eu passo a chamar o meu spinner assim:

<Spinner
  spinnerBackground={spinnerBackground}
  spinnerColor={spinnerColor}
/>

 

Antes de publicar no npm, podemos definir os tipos das props que nosso componente recebe instalando o prop-types com o comando npm -i --save prop-types e definindo os tipos no arquivo do componente:

import t from 'prop-types'

...

ButtonLoading.propTypes = {
  title: t.string,
  color: t.oneOf(['primary', 'danger']),
  loading: t.bool,
  styles: t.object,
  spinnerBackground: t.string,
  spinnerColor: t.string
}

Você pode ler mais a respeito sobre ele aqui. Acho que proptypes é algo para um artigo só dele... então não vou entrar muito em detalhes!

 

E pronto, agora sabemos como definir propriedades de "múltipla escolha" (type que pode receber primary e danger), propriedades booleanas (o loading) e como deixar nosso componente customizável recebendo estilos ou cores por parâmetro e utilizando onde queremos.


. . .

Poderia ficar horas escrevendo formas de customizar o componente, mas acho que isso já é um grande norte pra quem está começando!

Agora chegou a hora de nós publicarmos no npm!


. . .

Primeiramente, precisamos configurar algumas coisas...

O nome do pacote

O nome do pacote será o que usa para instalar npm install --save nome_do_pacote
Você pode defini-lo no package.json na propriedade name

A versão

A minha lib terá a versão pelo padrão Semantic Version, começando como 0.1.0

E caso eu adicione alguma cor, por exemplo, mudo o minor, ficando 0.2.0

Para publicar a lib é bastante simples: você só precisa executar o comando:

npm publish --access=public

 

Mas calma, antes de fazer isso você precisa ter um cadastro no NPM e configurar a sua máquina para poder publicar suas libs.

 

O cadastro é simples: entre em https://www.npmjs.com/ e cadastre-se!

 

Você ainda pode se cadastrar via terminal com o comando npm add user.

Será pedido um nome de usuário, uma senha e um e-mail (que ficará público).

Se você já tem cadastro, só precisará fazer login com o comando npm login.

Após isso, você pode verificar se seus dados estão corretamente configurados com o comando npm config ls.

 

Antes de publicar (fique tranquilo, já vamos chegar lá), precisamos configurar a build do nosso projeto.

Precisamos adicionar e configurar o babel para nos ajudar com a compilação do projeto.

Para adicionar utilize o comando npm -i @babel/cli @babel/core --save-dev

Crie o arquivo .babelrc na raíz do projeto com o seguinte script:

{
  "presets": [["react-app", { "absoluteRuntime": false }]]
}

 

Agora precisamos alterar o valor do script build no package.json para "rm -rf dist && NODE_ENV=production babel src/lib --out-dir dist --copy-files --ignore __tests__,spec.js,test.js,__snapshots__"

Com isso ele sempre irá apagar a pasta dist, mudando a variável de ambiente para production e gerando o build dos nossos arquivos dentro de src/lib com o babel e jogando para a pasta dist. Esse comando sempre apaga a pasta dist quando inicia para sempre gerar novos arquivos lá e não ocorrer conflitos durante o build.

 

Ainda no package.json, remova a linha "private": true e adicione essas linhas para o npm saber quais arquivos devem ser enviados para o npm:

"main": "dist/index.js",
"module": "dist/index.js",
"files": [
  "dist",
  "README.md"
],
"repository": {
  "type": "git",
  "url": "SEU_LINK_DO_REPOSITÓRIO"
},

 

Feito isso, rode no seu terminal o comando npm publish --access-public.

Agora que você tem a lib no npm, qualquer alteração que você fizer só irá precisar alterar a versão no package.json e rodar apenas npm publish!

 

Ah, e não esqueça de escrever como utilizar sua lib no README.md!


. . .

 

Bom, agora que você tem uma lib publicada no npm é hora de me despedir! Espero que goste!

Se ficar alguma dúvida, sugestão ou crítica, não exite em me contatar!

Abraços e até a próxima \o

Top comments (0)