Frontend React
Regras para todo frontend React. Este arquivo contém o que sempre se aplica; leia a referência correspondente antes de trabalhar naquele tópico.
| Tarefa | Leia |
|---|---|
| Pastas, camadas, slices, API pública, importações, barrel files | references/structure.md |
| Mergulhos profundos FSD: árvore de decisão, importações cruzadas, entidades, assets, posicionamento de auth/API, configuração do framework, migração | references/fsd/ (índice no final de structure.md) |
| Nomenclatura, tamanho de arquivo, props, design system, layouts, constantes | references/code-style.md |
| Componentes, hooks, effects, memoização, transições, listas longas, hidratação | references/hooks-and-rendering.md |
| Waterfalls, tamanho do bundle, code splitting, pré-carregamento, custo de re-renderização | references/performance.md |
| Dados do servidor, queries, mutações, loaders, parâmetros de busca, Zustand | references/data-and-state.md |
| Formulários, validação, erros de formulário | references/forms.md |
| Semântica, teclado, foco, contraste, live regions, testes de acessibilidade | references/accessibility.md (implementação React) + a skill frontend-accessibility (regras completas, auditorias) |
| Testes unitários, de componente e E2E, cobertura, mock de API | references/testing.md |
| Histórias (Stories), verificações de acessibilidade do Storybook, regressão visual | references/storybook.md |
| XSS, renderização de HTML/Markdown/saída LLM, autenticação, CSRF, CSP, variáveis de ambiente, logout | references/security.md |
| Versão do Node, gerenciador de pacotes, pre-commit + gitleaks, auditoria de dependências | references/tooling.md |
Traduções, troca de idioma, <html lang> | references/i18n.md |
| Configurando um novo projeto | references/setup.md |
| Imagem de contêiner para o frontend | references/docker.md + a skill docker-kubernetes |
Stack
- React 19 (≥ 19.2 para
useEffectEvente<Activity>) · TypeScript estrito - Renderização: SPA Vite ou modo framework React Router (SSR + hidratação). Regras marcadas com React Router framework only aplicam-se apenas lá. Sem Next.js, sem React Server Components, sem SWR.
- Roteamento: TanStack Router ou React Router — fixo por projeto, detecte a partir do código, nunca misture.
- Estado do servidor: TanStack Query · Estado do cliente: Zustand
- Formulários: React Hook Form + Zod ou TanStack Form + Zod — fixo por projeto
- Validação: Zod em cada fronteira (respostas de API, formulários, parâmetros de busca, env, armazenamento,
postMessage) - Ferramentas: Biome (lint + format), Steiger (regras FSD), Vitest + Testing Library, Playwright, Storybook
- Sem React Compiler → a memoização é manual, mas apenas após medição.
Estrutura — Feature-Sliced Design
Camadas app → pages → widgets → features → entities → shared; importações apenas para baixo; sem importações entre slices da mesma camada; cada slice é importado apenas através de seu index.ts com exports nomeados explícitos (sem export *). shared/ui e shared/lib têm um índice por componente/biblioteca. Comece com app, pages, shared; sem pastas de camada vazias. O código permanece na página até que a regra de extração seja válida — usado em vários lugares agora, um motivo para mudar independente de qualquer consumidor, uma responsabilidade focada; todos os três, a duplicação é aceitável até então. widgets é desencorajado: apenas para um bloco composto reutilizado em várias páginas que não pode viver em uma página (widgets existentes permanecem válidos). Detalhes: references/structure.md, livro de regras upstream references/fsd/rules.md.
- Um componente por arquivo, um hook por arquivo, ~150 linhas por componente; componentes prefixados com o nome do slice (
references/code-style.md). - Design system primeiro: use os próprios componentes de
shared/ui/; nunca importeshared/ui/primitives/(saída da CLI da biblioteca de UI, nunca editada) fora deshared/ui/. Nenhum novo CSS antes de verificar o que os componentes, props e tokens do design system podem fazer.
Componentes e hooks — sempre
- Nunca defina um componente dentro de outro componente — ele remonta a cada renderização.
- Derive, não sincronize: valores computáveis a partir de props/estado são calculados durante a renderização. Sem
useEffectque copie props ou estado para o estado. Redefina comkey. - Ações do usuário executam em event handlers, não em effects acionados por flags de estado.
- Effects apenas sincronizam com sistemas externos, com dependências primitivas estreitas, um objetivo por effect e uma limpeza. Nunca silencie a regra exhaustive-deps.
setState(prev => …)quando o próximo valor depende do anterior;useState(() => expensive())para valores iniciais caros.- Nunca mude props ou estado:
toSorted(),toReversed(),toSpliced(),with(), spread. {count > 0 ? <X /> : null}— nunca&&com um número à esquerda.- Sem
fetchemuseEffect; dados do servidor vêm do TanStack Query ou de um route loader. memo/useMemo/useCallbackapenas após perfilamento ou quando a estabilidade referencial for necessária.- Erros nunca são engolidos: sem
catchvazio, sem.catch(() => {}). Toda rota tem uma error boundary; toda query tem UI de carregamento, erro e vazio.
Dados e estado — sempre
- Função de requisição → hook → componente. HTTP apenas através do cliente em
shared/api/; nunca importe um cliente HTTP em hooks ou componentes. - Dados do servidor vivem apenas no TanStack Query, através de uma fábrica de chaves de query com
queryOptions; as respostas são analisadas com Zod na função de requisição. - Acesso a recursos simples, CRUD e fábricas de chaves de query vivem em
shared/api(ou na página/feature que sozinha os usa);entities/<x>/apiapenas para requisições com regras de domínio ou mapeamento dessa entidade. - Mutações invalidam (ou atualizam) toda query afetada.
- Estado de URL (filtros, ordenação, paginação, abas) vive em parâmetros de busca tipados e validados com Zod — nunca analisados manualmente de
window.location. - Zustand apenas para estado de cliente compartilhado; sempre com um seletor; stores persistidas usam
version,migrateepartialize, e não contêm dados sensíveis. - Carregue dados de rota no route loader (
queryClient.query({ ...options, staleTime: 'static' }), anteriormenteensureQueryData) e em paralelo, não em componentes aninhados um após o outro.
Acessibilidade — incorporada, nunca adicionada depois
Alvo: WCAG 2.2 AA. Parte da definição de pronto para cada componente e página. A skill frontend-accessibility contém as regras completas e o procedimento de auditoria — carregue-a para toda mudança de UI.
- HTML semântico primeiro:
<button>para ações,<a>/<Link>para navegação,<label>para cada campo, landmarks, um<h1>e headings ordenados. ARIA apenas quando nenhum elemento nativo se encaixa. - Teclado: tudo acessível e operável com o teclado; sem
tabIndexpositivo; sem armadilhas de teclado. - Foco visível em todo elemento interativo (
:focus-visible, contraste ≥ 3:1). - Gerenciamento de foco: ao mudar de rota, defina o título da página e mova o foco para o
<h1>ou<main>; diálogos prendem o foco, fecham comEscapee retornam o foco ao gatilho. - Nomes: botões de ícone têm
aria-label; imagens têmalt(alt=""se decorativa). - Contraste 4.5:1 para texto, 3:1 para componentes de UI; cor nunca é o único sinal.
- Movimento reduzido respeitado; live regions (
role="status"/role="alert") para resultados assíncronos e erros. - Testes consultam por role e nome acessível; histórias passam no addon de acessibilidade; páginas críticas passam no axe no Playwright.
Testes — escritos com a funcionalidade, não depois
- Vitest + Testing Library testes unitários e de componente para cada funcionalidade, na mesma alteração. Teste o comportamento através da UI (roles, labels,
user-event), não detalhes de implementação. - Cobertura ≥ 80% linhas e ≥ 80% branches, aplicada por limites do Vitest no CI.
- Playwright E2E para cada fluxo de usuário crítico (login, fluxos de negócio principais, pagamento/checkout, permissões): localizadores baseados em role, sem esperas fixas, estado de autenticação reutilizado, varredura axe em páginas-chave.
- História Storybook para cada componente de UI compartilhado/reutilizável, cobrindo todos os estados (padrão, carregando, vazio, erro, desabilitado, conteúdo longo). Viewport desktop por padrão; viewports móveis apenas quando o projeto requer layouts responsivos.
- Regressão visual via Storybook + screenshots do Playwright; testes de snapshot apenas com moderação e direcionados.
Segurança — sempre
- Sem
dangerouslySetInnerHTMLsem DOMPurify; fora do React usetextContent, nuncainnerHTML. Saída de modelo e Markdown nunca renderizam como HTML bruto. - Sem tokens ou dados sensíveis em
localStorage/sessionStorage/IndexedDB. Autenticação é um cookie de sessãoHttpOnlydefinido pelo backend; para OIDC, prefira um backend-for-frontend. - Requisições de mudança de estado enviam o cabeçalho CSRF;
credentials: 'include'apenas para a própria API. - Variáveis
VITE_*são públicas — sem segredos nelas, jamais. - Destinos
?redirect=são apenas caminhos relativos de mesma origem (redirecionamento aberto). - Logout limpa a sessão do servidor, o cache do TanStack Query e todos os stores persistidos.
- CSP como cabeçalho HTTP com
object-src 'none',base-uri 'none',frame-ancestors. - Handlers
postMessageverificamevent.origin; nunca mescle objetos não confiáveis (poluição de protótipo). - O frontend nunca aplica autorização — o backend o faz [ASVS 8.3.1].
TypeScript e Biome
strictativado (padrão desde TypeScript 7 — mantenha explícito); tambémnoUncheckedIndexedAccess,verbatimModuleSyntax,moduleResolution: "bundler",libcomES2023+DOM. TypeScript 7 definetypescomo[]por padrão — liste"vite/client"explicitamente;baseUrlse foi, usepaths("@/*": ["./src/*"]).- Sem
any(useunknowne restrinja), sem non-null assertions para silenciar erros, sem@ts-ignore(@ts-expect-errorcom um motivo se inevitável). Sem números ou strings mágicos — constantes nomeadas emshared/config/ou noconfig/modeldo slice. - Tipos de dados externos vêm de schemas Zod (
z.infer/z.output), não de interfaces escritas à mão que podem divergir. - Biome: regras recomendadas mais
noNestedComponentDefinitions,noReExportAllenoConsole(não no conjunto recomendado);noBarrelFilepermanece desligado para arquivosindex.tsde slice (references/structure.md). biome ci,tsc --noEmit,steiger ./srceknippassam localmente e no CI. Não desabilite regras inline sem um comentário explicando o porquê.- Comentários em inglês; TODOs usam o marcador TODO do projeto.
Higiene do repositório — sempre
- Versão do Node fixada:
.nvmrc(LTS),enginesempackage.jsoncomengine-strict,packageManagercom a versão exata do npm/pnpm; lockfile comprometido. - pre-commit instalado para commit e push: gitleaks em mudanças staged e em todos os commits não enviados, Biome;
tsc, testes Vitest relacionados e a auditoria de dependências no push. Nunca ignore com--no-verify. - Auditoria de dependências no CI em cada MR e em um cronograma.
Detalhes: references/tooling.md.
Docker e implantação
Imagens de contêiner, .dockerignore, Compose e Kubernetes são cobertos pela skill docker-kubernetes; o fluxo de trabalho e checklist do frontend estão em references/docker.md. Toda imagem tem um .dockerignore. Fatos específicos do frontend a respeitar lá:
- Valores
VITE_*são incorporados ao bundle no momento da build. Uma imagem para vários ambientes precisa de configuração em tempo de execução: sirva umconfig.json(ouconfig.js) que é escrito na inicialização do contêiner a partir de variáveis de ambiente e buscado/validado na inicialização do app — ainda público, ainda sem segredos. - Um SPA Vite é arquivos estáticos: sirva-os a partir de um servidor web com fallback para
index.htmlem rotas do lado do cliente, cache longo para assets com hash,no-cacheparaindex.htmle os cabeçalhos de segurança dereferences/security.md. - Modo framework React Router (SSR) precisa de um servidor Node em tempo de execução (
react-router-serveou um servidor personalizado) — não é uma implantação estática.
Após escrever
Para uma revisão de segurança do resultado, sugira a skill appsec-review.
Fontes
Combinado das melhores práticas React da Vercel Engineering (github.com/vercel-labs/agent-skills, react-best-practices, Licença MIT) — adaptado de Next.js para Vite/React Router com TanStack Query; IDs de regras mantidos para rastreabilidade — e do OWASP Secure Agent Playbook (CC BY 4.0; OWASP ASVS 5.0). Estrutura segue Feature-Sliced Design (feature-sliced.design, fsd.how); references/fsd/ é adaptado da skill oficial do FSD agent (github.com/feature-sliced/skills, Licença MIT). Acessibilidade visa WCAG 2.2.