Pular para o conteúdo principal

Manual do desenvolvedor

O Tangram adota o modelo Trunk-Based Development (TBD), no qual a branch main é a principal referência do projeto e a única branch permanente de longa duração. As alterações são desenvolvidas em branches temporárias (feature branches, bugfixes ou hotfixes) criadas a partir da main. Após revisão, validação e aprovação, os Pull Requests são mergeados diretamente na main.

Deste modo, as branches do projeto geralmente são classificadas como:

  • Proncipal (main): Branch principal do projeto e origem de todas as releases.
  • Feature Branches: Branches temporárias utilizadas para desenvolvimento de funcionalidades maiores ou iniciativas compostas por múltiplos Pull Requests.
  • Hotfix/Bugfix Branches: Branches temporárias utilizadas para correções e melhorias pontuais.

Estratégia de branches

Novas funcionalidades ou grandes melhorias

Para iniciativas como épicos, waves ou projetos que envolvam múltiplas entregas, recomenda-se a utilização de uma feature branch.

Exemplo:

main
└── FRONTPLAT-feature-branch-design-token-migration
├── FRONTPLAT-1234-update-colors
├── FRONTPLAT-5678-update-spacing
└── FRONTPLAT-9012-update-components

Nesse modelo, os Pull Requests são mergeados inicialmente na feature branch e, após a conclusão da iniciativa, a feature branch é mergeada na main.

Correções e melhorias pontuais

Para correções de bugs, melhorias de performance ou ajustes de pequeno escopo, a branch deve ser criada diretamente a partir da main e o Pull Request deve ser aberto diretamente para a main.

Exemplo:

  main
├── fix-button-color
├── improve-datepicker-performance
└── update-icon-library

O Tangram é construído usando uma coleção de pacotes, todos feitos no mesmo repositório Git, chamado monorepo.

Usamos duas ferramentas para nos ajudar a gerenciar as dependências de instalação e publicar os pacotes:

  • Yarn workspaces para lidar com dependências em todos os pacotes
  • Lerna para publicar pacotes, marcar versões, entre outros

Antes de instalar as dependências, é necessário configurar o .npmrc na máquina ou projeto, incluindo credenciais jFrog. Para mais informações acesse nossa wiki.

Para instalar todas as dependências neste projeto, é necessário instalar o Yarn e executar o seguinte comando no terminal:

yarn install

Assim será instalada todas as dependências de cada pacote do projeto. Além disso, é possível conectar os pacotes que estamos desenvolvendo.

yarn setup

Assim serão vinculados os pacotes e dependências. Além disso, construirá cada pacote.

Para criar todos os arquivos do pacote, execute o seguinte comando:

yarn build

Agora você deve estar com tudo pronto para começar a contribuir com o Tangram!

Documentação

Playground

Utilizamos o Ladle como ferramenta de playground. Para iniciá-lo você pode executar o seguinte comando:

yarn playground start

Docusaurus

Para iniciar o Docusaurus com documentação pública, você pode executar o seguinte comando:

// documentação em inglês
yarn docs start
// documentação em português
yarn docs start:br

Tarefas comuns

Algumas das tarefas que você pode precisar executar:

Tarefas comuns
ComandoUtilização
yarn buildUtilize lerna para executar o script build em cada pacote
yarn cleanRedefine o estado do projeto removendo todos os node_modules e executando o script clean em cada pacote
yarn formatFormata os arquivos usando o Prettier e verifica se os arquivos foram formatados
yarn testExecuta teste nos arquivos em cada pacote do projeto
yarn lintExecuta o eslint nos arquivos no projeto
lerna add <dependency-name> --scope=<package-name>Para adicionar alguma dependência de em um pacote específico (workspace). Use -D para adicionar no modo dev

Publicação da documentação

Toda branch gera automaticamente uma versão da documentação em staging, a documentação ficará disponível para validação após a conclusão da pipeline.

Após o merge na Main, a documentação é publicada automaticamente em produção.

Convenções para os commits

Este projeto segue um formato estruturado para escrever mensagens de commit. O principal benefício é que podemos usar esses detalhes para gerar automaticamente coisas como logs de mudanças, por exemplo, além de esclarecer a quais mudanças correspondem quando olhamos nosso histórico Git.

Nos baseamos no padrão criado pela equipe AngularJS.

Formato das mensagens

Dica

Partes desta seção foram duplicadas das convenções de commit do AngularJs.

Cada mensagem de commit consiste em um cabeçalho, um corpo e um rodapé. O cabeçalho tem um formato específico que inclui um tipo, um escopo e um assunto:

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

O cabeçalho é obrigatório e o escopo do cabeçalho é opcional. Existem algumas regras de validação que também aplicamos:

  • O cabeçalho deve sempre ter menos de 72 caracteres
  • Qualquer linha no corpo do commit deve ter menos de 100 caracteres

Muitas dessas regras são para ajudar na integração do git com ferramentas comuns. Verificamos este formato de commit usando uma ferramenta chamada commitlint.

Tipo

Deve ser um dos seguintes:

  • feat: Um novo recurso
  • fix: Uma correção de bug
  • docs: Alterações apenas na documentação
  • test: Adicionar testes ausentes ou corrigir testes existentes
  • refactor: Uma alteração de código que não corrige um bug nem adiciona um recurso
  • perf: Uma alteração de código que melhora o desempenho
  • revert: Uma mudança de código que reverte um commit anterior
  • chore: Mudanças no processo de construção, ferramentas, dependências (package.json por exemplo)

Assunto

O assunto contém uma descrição sucinta da mudança:

  • use o tempo presente imperativo: "altera" e não "alterado" nem "alterações"
  • não coloque a primeira letra em maiúscula
  • sem ponto (.) no final

Corpo

Assim como no assunto, use o imperativo, presente: "altera" e não "alterado" nem "alterações". O corpo deve incluir a motivação para a mudança e contrastar isso com o comportamento anterior.

O rodapé deve conter todas as informações sobre alterações significativas. Quando for necessário utilizar o Breaking Changes ele deve começar com a palavra BREAKING CHANGE: com um espaço ou duas novas linhas.

Exemplos

Feature (feat)
// Adicionar uma nova funcionalidade a um trecho de código é considerado um recurso.
// Isso pode ser visto como uma extensão de uma API existente.
- function MyComponent({ propA }) {
+ function MyComponent({ propA, propB }) {
// ...
}
Bug fix (fix)
// Atualizar uma implementação para corrigir uma falha no código existente
// é considerado uma correção de bug
function add(a, b) {
- return a - b;
+ return a + b;
}

Pacotes

Estes são os pacotes do projeto:

  • @resultadosdigitais/tangram-design-tokens
    • Localizado em packages/design-tokens
    • Armazena todos os tokens de design, como valores para cores, espaçamentos, fontes, etc.
  • @resultadosdigitais/tangram-react-icons
    • Localizado em packages/react-icons
    • Armazena todos os ícones SVG e os constrói como React Icons
  • @resultadosdigitais/tangram-components
    • Localizado em packages/components
    • Responsável pelos componentes principais do Tangram, como Button, Input, etc.
  • @resultadosdigitais/tangram-react-datepicker
    • Localizado em packages/react-datepicker
    • Responsável pelos componentes de seleção de data, como DatePicker, DateRangePicker, etc.
  • @resultadosdigitais/tangram-shell
    • Localizado em packages/shell
    • Responsável pelo componente de navegação global Shell

Estilo de codificação

Componentes em ReactJS

É importante manter um padrão de escrita de nossos componentes, principalmente devido à quantidade de componentes que teremos, para manter um padrão que nos permita ler e modificar com mais facilidade.

Exportando componentes

Os componentes desenvolvidos precisam ser exportados tanto no ponto de entrada principal quanto na pasta de entrada de cada componente.

1. Ponto de entrada principal

Exporte o componente no ponto de entrada principal localizado em packages/components/src/index.js:

export { default as Component } from './Component';
export * from './Component';

Com isso é possível acessar o componente dentro do pacote.

import { Component } from '@resultadosdigitais/tangram-components';
2. Pasta de entrada

Exporte a pasta do componente para disponibilizar a inclusão apenas o que for necessário packages/components/src/Component/index.js:

export { default } from './Component';
export { default as SubComponent } from './SubComponent';

Com isso é possível acessar a pasta do componente e evitar incluir todos os componentes no bundle.

import Component

Exportando enumeradores

Atenção!

É importante mapear os enums nos componentes que precisam deles, em vez de fazer referência a um valor padrão para todos os componentes, pois isso nos ajuda a evitar problemas com a alteração desses valores. Portanto, mesmo que outros componentes compartilhem os mesmos valores, é válido mapear esses valores em seu componente.

Exportamos enumeradores como um utilitário para nos ajudar na implementação para evitar que forneçamos um valor inexistente. Observe que os enumeradores são escritos no plural quando o exportamos, e o prop é escrito no singular.

const Button = ({ kind }) => {
// ... component code
};

// No plural
Button.kinds = {
default: KINDS.DEFAULT,
primary: KINDS.PRIMARY,
success: KINDS.SUCCESS
};

Button.propTypes = {
// No singular
kind: PropTypes.oneOf([
Button.kinds.default,
Button.kinds.primary,
Button.kinds.success
])
};

Exemplo dos enumeradores na implementação com a nova definição.

<Button kind={Button.kinds.primary}>Action</Button>

Arquivos e pastas

@resultadosdigitais/tangram-components

Ficam na pasta packages/components/ e tambem temos um ponto de entrada localizado em /src/index.js que exporta todos os componentes:

export { default as Button } from './Button';
  • Todos os componentes pertencem a /src em sua própria pasta
  • Nomeie arquivos e pastas usando a forma singular, não no plural
  • Há excessões que é preciso lidar com componentes cujo nome faz sentido no plural, por exemplo: Tabs
...
Button
- Button.test.js
- Button.js
- constant.js
- index.js
- ...
  • Button.test.js: Arquivo com testes de componentes
  • Button.js: Código do componente com o estilo dentro (styled-components)
  • constant.js: Responsável por armazenar as constantes relacionadas ao componente
  • index.js: Ponto de entrada para exportar o componente
  • config.js: Responsável por armazenar configurações e funções auxiliares

A pasta helper, localizada em /src/helper, é responsável por armazenar todas as configurações comuns, funções, hooks, etc.

@resultadosdigitais/tangram-react-icons

Atenção

Ao adicionar um novo ícone remova todos os valores fill fill="#000" dentro de cada SVG. Esse valor é adicionado automaticamente por scripts de ícones em React.

Todos os ícones pertencem a packages/react-icons/svg em sua própria pasta. Nomeie os arquivos usando a forma singular, não no plural.

- align-center.svg
- align-justify.svg
- ...

Todas as configurações relacionadas à construção estão em packages/react-icons nos seguintes arquivos:

- svgr.config.js
- babel.config.js
- rollup.config.js

@resultadosdigitais/tangram-design-tokens

Todos os tokens pertencem a packages/design-tokens/src nos seguintes arquivos:

- base.json
- theme.json
- index.js

Todas as configurações relacionadas à construção estão em packages/design-tokens/tasks.

Pull request

Para mantermos nosso histórico de commits limpo, compreensível e automatizado, todos os Pull Requests deverão seguir as convenções de nomenclatura abaixo.

Regra geral

Independente da branch, o título do seu PR deve ser escrito sempre em português e ser composto por três elementos:

Verbo + Alteração + Contexto

Isso garante legibilidade dos changelogs que são gerados e organizados automaticamente no processo de release.

Estrutura detalhada

  • Verbo: Sempre no presente do indicativo (ex: adiciona, corrige, remove, atualiza).
  • Alteração: Uma descrição objetiva e detalhada do que foi feito.
  • Contexto: O componente, página, serviço ou módulo que sofreu a alteração.

Exemplo:

Adiciona suporte para o estado de de loading no componente button
| | |
verbo alteração contexto
Dica

É uma boa prática não utilizar prefixos como "feat:", "fix:", "chore-" e outros.
A descrição textual deve ser clara o suficiente por si só.

Prefixo (dev)

Caso a alteração seja uma branch de desenvolvimento que será mergeada em uma feature-branch, é possivel usar o marcador (dev) no início do título para que a alteração seja omitida do changelog aparecendo apenas agrupada na PR da feature-branch.

Exemplo:

(dev) corrige desalinhamento do ícone no cabeçalho da dashboard
|
prefixo

Como fica o changelog com pull requests omitidas:

💥 Breaking Change

  • título da feature-branch que deverá estar no changelog (verbo + alteração + contexto) #94 (@autor1) #89 (@autor2), #90 (@autor2), #92 (@autor3)

Neste exemplo, #94 (@autor1) é a PR da feature-branch, cujo título deve descrever o resultado final para quem lê o changelog, não o último commit isolado. Enquanto, #89 (@autor2) / #90 (@autor2) / #92 (@autor3), são PRs de desenvolvimento (dev-branches) agrupadas e foram omitidas com o prefixo (dev) acrescentado ao título da pull request.

Atenção

O prefixo (dev) não deve ser usado no título de PRs que apontam diretamente para branch main.

Labels

  • Todo Pull Request deve ter uma label para indicar o tipo de mudança. Você pode adicionar mais de uma, se necessário.

  • O cálculo das versões é realizado automaticamente através das ferramentas Auto e Lerna com base nas labels configuradas no Pull Request.

Tipos de labels

LabelPropósitoDescrição
version:majorMudanças que quebram compatibilidade (breaking changes). Incrementa a versão major (ex.: 1.5.02.0.0).Incrementa versão major ao mergear com version:release
version:minorNovas funcionalidades ou melhorias compatíveis. Incrementa a versão minor (ex.: 1.5.01.6.0).Incrementa versão minor ao mergear com version:release
version:patchCorreções de bugs e hotfixes. Incrementa a versão patch (ex.: 1.5.01.5.1).Incrementa versão patch ao mergear com version:release
version:performanceMelhorias de performance de funcionalidades existentes. Incrementa a versão patch.Incrementa versão patch ao mergear com version:release
version:releaseAutoriza a publicação no npm. Deve ser combinada com uma label de versionamento (major, minor, patch ou performance). No PR, também dispara a publicação de uma versão canary para validação.Autoriza a publicação ao ser combinada com alguma das labels uma acima
version:internalAlterações que afetam apenas a API interna (CI, tooling, refactors internos).Nâo incrementa a versâo
version:docsAlterações que afetam apenas a documentação de produção.Nâo incrementa a versâo
version:dependenciesAtualização de versão de uma ou mais dependências, sem impacto funcional direto nos pacotes.Nâo incrementa a versâo
info

Para publicar no npm, o PR precisa de version:release + uma label de versionamento (version:major, version:minor, version:patch ou version:performance). Labels como version:internal, version:docs e version:dependencies não exigem version:release.

dica

Confira as recomendações na seção de Publicações e lançamentos antes de publicar novas vesões.

Issues

Se o seu pull request está resolvendo algum problema, é uma boa prática vincular a issue à sua solicitação de pull request.

Deploy

Canary Releases

Caso o Pull Request possua uma label de versionamento (version:major, version:minor, version:patch ou version:performance) juntamente com a label version:release a pipeline publicará automaticamente uma versão canary. As versões canary permitem validar alterações antes da publicação oficial na main.

Exemplo:

Versões Canary
tangram-components@8.22.0-canary.2801.55678.0
tangram-design-tokens@3.14.0-canary.2801.55678.0
tangram-react-datepicker@4.12.0-canary.2801.55678.0
tangram-react-icons@3.17.0-canary.2801.55678.0

Caso a label version:release seja removida antes do merge, nenhuma release oficial será publicada.

Production

O deploy de produção é executado automaticamente sempre que uma alteração é mergeada na main.

Após o merge, a pipeline será responsável por:

  • Calcular a próxima versão;
  • Gerar o changelog;
  • Atualizar o versionamento dos pacotes;
  • Publicar a release;
  • Publicar a documentação em produção.

Não é necessário criar Pull Requests entre branches de release ou executar processos manuais para promover alterações para produção.

O deploy de produção é executado sempre que uma branch é mergeada na branch main. O Circle CI iniciará a implantação para AWS e quando o processo for finalizado o resultado será exibido em Tangram.

Caso seja necessário publicar uma nova versão, só é necessário adicionar uma das labels de versão e a label version:release no pull request.

Publicações e lançamentos

Para publicar uma nova versão do Tangram:

  1. Criar e concluir o desenvolvimento em uma branch derivada da Main.
  2. Abrir um Pull Request.
  3. Adicionar a label de versionamento apropriada.
  4. Adicionar a label version:release.
  5. Garantir que os testes e validações estejam aprovados.
  6. Obter aprovação de revisão.
  7. Realizar o merge na branch main. Após o merge, a publicação ocorrerá automaticamente.

Próximas versões

Certifique-se de testar a versão lançada! Se você quiser ser extremamente cuidadoso, pode publicar uma versão canary para realizar os testes e validações.

Não se esqueça de remover a label version:release caso só queira gerar a canary e não publicar uma versão no merge com a main.

Caso tenha esquecido de adicionar a label, temos duas opções:

  • Vá até o último pull request, adicione a label version:release e rode o CI novamente.
  • Crie um novo pull request com a label version:release, espere o CI rodar para publicar a canary e feche o pull request.

O GitHub, como outros serviços, não permite que você crie um pull request sem pelo menos um commit em mais de uma branch base. Para resolver isso é necessário criar um commit extra:

git checkout -b empty-release --track origin/main
git commit --allow-empty -m "Release review"
git push origin empty-release

FAQ

Como publicar uma Canary Release?

  1. Abra um Pull Request.
  2. Adicione a label de versionamento correspondente.
  3. Adicione a label version:release.
  4. Aguarde a execução da pipeline.

Uma versão canary será gerada automaticamente para validação antes da publicação oficial.

Quando devo utilizar uma Feature Branch?

Feature branches devem ser utilizadas para iniciativas maiores que envolvam múltiplos Pull Requests ou entregas graduais. Para correções simples ou melhorias pontuais, recomenda-se abrir o Pull Request diretamente para a main.

Como faço para instalar uma dependência?

Dica

É importante manter as dependências comuns na raiz e deixar o Lerna gerenciá-las. Ele fornece maior desempenho de instalação.

  • Para instalar uma dependência comum para todos os pacotes, você pode executar yarn add -W <dependency-name>
  • Para instalar uma dependência para apenas um pacote, você pode executar lerna add <dependency-name> --scope=<package-name>
    • Exemplo: lerna add -D lodash --scope=@resultadosdigitais/tangram-components

Como faço para adicionar um novo ícone à biblioteca do react-icons?

Dica

O ícone precisa estar no formato svg e, se tiver mais de uma palavra no nome, é necessário separá-las com hífen.

  • Após adicionar o novo ícone ao diretório react-icons/svg, você pode executar yarn build dentro de react-icons para gerar o componente
  • Ao abrir o pull request, selecione a label version:release, para gerar uma canary, possibilitando testar o código em staging para verificar se o novo ícone foi corretamente adicionado à documentação.

Feedback

Para reportar algum problema ou sugerir alterações, use nosso formulário de melhorias ou, se preferir, abra uma issue no nosso Github.