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:
| Comando | Utilização |
|---|---|
yarn build | Utilize lerna para executar o script build em cada pacote |
yarn clean | Redefine o estado do projeto removendo todos os node_modules e executando o script clean em cada pacote |
yarn format | Formata os arquivos usando o Prettier e verifica se os arquivos foram formatados |
yarn test | Executa teste nos arquivos em cada pacote do projeto |
yarn lint | Executa 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
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.
Rodapé
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
// 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 }) {
// ...
}
// 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.
- Localizado em
@resultadosdigitais/tangram-react-icons- Localizado em
packages/react-icons - Armazena todos os ícones SVG e os constrói como React Icons
- Localizado em
@resultadosdigitais/tangram-components- Localizado em
packages/components - Responsável pelos componentes principais do Tangram, como
Button,Input, etc.
- Localizado em
@resultadosdigitais/tangram-react-datepicker- Localizado em
packages/react-datepicker - Responsável pelos componentes de seleção de data, como
DatePicker,DateRangePicker, etc.
- Localizado em
@resultadosdigitais/tangram-shell- Localizado em
packages/shell - Responsável pelo componente de navegação global
Shell
- Localizado em
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
É 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
/srcem 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 componentesButton.js: Código do componente com o estilo dentro (styled-components)constant.js: Responsável por armazenar as constantes relacionadas ao componenteindex.js: Ponto de entrada para exportar o componenteconfig.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
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
É 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.
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
| Label | Propósito | Descrição |
|---|---|---|
version:major | Mudanças que quebram compatibilidade (breaking changes). Incrementa a versão major (ex.: 1.5.0 → 2.0.0). | Incrementa versão major ao mergear com version:release |
version:minor | Novas funcionalidades ou melhorias compatíveis. Incrementa a versão minor (ex.: 1.5.0 → 1.6.0). | Incrementa versão minor ao mergear com version:release |
version:patch | Correções de bugs e hotfixes. Incrementa a versão patch (ex.: 1.5.0 → 1.5.1). | Incrementa versão patch ao mergear com version:release |
version:performance | Melhorias de performance de funcionalidades existentes. Incrementa a versão patch. | Incrementa versão patch ao mergear com version:release |
version:release | Autoriza 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:internal | Alterações que afetam apenas a API interna (CI, tooling, refactors internos). | Nâo incrementa a versâo |
version:docs | Alterações que afetam apenas a documentação de produção. | Nâo incrementa a versâo |
version:dependencies | Atualização de versão de uma ou mais dependências, sem impacto funcional direto nos pacotes. | Nâo incrementa a versâo |
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.
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:
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:
- Criar e concluir o desenvolvimento em uma branch derivada da Main.
- Abrir um Pull Request.
- Adicionar a label de versionamento apropriada.
- Adicionar a label
version:release. - Garantir que os testes e validações estejam aprovados.
- Obter aprovação de revisão.
- 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:releasee rode o CI novamente. - Crie um novo pull request com a label
version:release, espere o CI rodar para publicar acanarye 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?
- Abra um Pull Request.
- Adicione a label de versionamento correspondente.
- Adicione a label
version:release. - 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?
É 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
- Exemplo:
Como faço para adicionar um novo ícone à biblioteca do react-icons?
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 executaryarn builddentro dereact-iconspara 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.