Skip to content

perf: dividir o bundle por rota (−60% na carga inicial) - #38

Merged
janeiaraujo merged 2 commits into
feat/i18n-telas-secundariasfrom
perf/code-splitting
Aug 3, 2026
Merged

perf: dividir o bundle por rota (−60% na carga inicial)#38
janeiaraujo merged 2 commits into
feat/i18n-telas-secundariasfrom
perf/code-splitting

Conversation

@janeiaraujo

Copy link
Copy Markdown
Owner

Base: este PR está empilhado sobre feat/i18n-telas-secundarias (#37),
porque os dois mexem no bloco de imports do App.jsx e sairia conflito. Ao
mergear o #37, o GitHub re-aponta este para a main sozinho.

O problema

O frontend saía num chunk único de 2,0 MB (597 kB gzip). Quem abria a tela
de login baixava a aplicação inteira — o editor TipTap, os gráficos, todas as
telas de admin — para ver um formulário com dois campos. O Vite avisava disso a
cada build.

O que mudou

41 rotas passam a entrar por lazy(), com um Suspense em volta usando o mesmo
spinner que as rotas protegidas já usam (para a tela não mudar de aparência
conforme o chunk esteja em cache ou não).

Login e Register ficam estáticos de propósito. São o primeiro contato de
quem chega sem sessão; adiar essas duas trocaria um bundle grande por um flash
de spinner logo na abertura — pioraria a impressão em vez de melhorar.

Resultado

antes depois
carga inicial 2400 kB 973 kB
carga inicial (gzip) 649 kB 261 kB
chunks JS 1 87

−60% no que o visitante baixa para ver a primeira tela.

Verificação no navegador

Não confiei só no relatório do build — medi a rede de verdade:

  • Login carrega 26 chunks, e o chunk do editor (570 kB: TipTap +
    ProseMirror + highlight.js, compartilhado por KBCreate e KBEdit) não está
    entre eles
    — que era exatamente o peso morto que motivou a mudança
  • Navegando para /forgot-password, o chunk ForgotPassword-*.js é buscado sob
    demanda (200) e a tela renderiza normalmente — Suspense e lazy funcionando
    ponta a ponta

npm test → 7 passam · vite build ok.

Um detalhe do caminho

A primeira tentativa de reescrita falhou em silêncio: o replace do bloco
<Routes> não casou (a função tinha ganhado o hook do i18n na linha anterior),
mas o replace do fechamento casou — resultado, JSX desbalanceado. O build
pegou na hora, mas o aprendizado ficou: toda substituição de código agora passa
por asserção, em vez de falhar calada.

O frontend saia num chunk unico de 2,0 MB (597 kB gzip): quem abria a
tela de login baixava a aplicacao inteira, incluindo o editor TipTap, os
graficos e todas as telas de admin, para ver um formulario com dois
campos. O Vite avisava disso a cada build.

41 rotas passam a entrar por lazy(), com um Suspense em volta. Login e
Register ficam estaticos de proposito: sao o primeiro contato de quem
chega sem sessao, e adiar essas duas trocaria o bundle grande por um
flash de spinner logo na abertura.

Carga inicial: 2400 kB -> 973 kB (649 kB -> 261 kB gzip), ~60% a menos.

Medido no navegador: o login busca 26 chunks e o chunk do editor
(570 kB, TipTap + ProseMirror + highlight.js, compartilhado por KBCreate
e KBEdit) nao esta entre eles. Navegando para /forgot-password, o chunk
proprio da rota e buscado sob demanda e a tela renderiza.
Copilot AI review requested due to automatic review settings August 3, 2026 20:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Divide o bundle do frontend por rota, migrando a maior parte das telas para carregamento sob demanda com React.lazy() + Suspense, reduzindo significativamente a carga inicial (especialmente para visitantes na tela de login).

Changes:

  • Converte 41 rotas para carregamento lazy via React.lazy(() => import(...)).
  • Envolve o bloco de <Routes> em um <Suspense> com fallback de spinner consistente.
  • Mantém Login e Register como imports estáticos para preservar a experiência de primeira carga.
Suppressed comments (2)

frontend/src/App.jsx:64

  • Comentário com palavras em português sem acentos ("nao", "aparencia", "ja"), o que parece erro ortográfico.
// Enquanto o chunk da rota chega. Usa o mesmo spinner das rotas
// protegidas, para a tela nao mudar de aparencia conforme o chunk ja
// esteja em cache ou nao.

frontend/src/App.jsx:16

  • Comentário com palavra em português sem acento ("unico" → "único").
// O resto entra por rota. Antes tudo vinha num chunk unico de 2 MB, que
// todo visitante baixava inteiro para ver a tela de login.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread frontend/src/App.jsx
Comment on lines +9 to +11
// Telas de entrada: estaticas de proposito. Sao o primeiro contato de
// quem chega sem sessao, e adiar o carregamento delas trocaria um bundle
// grande por um flash de spinner logo na abertura.
O gatilho tinha filtro 'branches: [main]' no pull_request, entao um PR
empilhado sobre outra branch nao recebia nenhum check - foi o que
aconteceu com este proprio PR, aberto sobre feat/i18n-telas-secundarias
para evitar conflito no App.jsx.

Sem checks, a protecao da main so cobre o PR de baixo da pilha: o de
cima entra sem ninguem ter rodado teste nele.
@janeiaraujo

Copy link
Copy Markdown
Owner Author

Adicionei um commit fora do escopo do PR, e quero deixar explícito o porquê: este PR estava sem nenhum check.

O gatilho do CI tinha pull_request: branches: [main], então um PR empilhado sobre outra branch — como este, aberto sobre feat/i18n-telas-secundarias para evitar conflito no App.jsx — não disparava nada. Efeito prático: a proteção da main só cobria o PR de baixo da pilha; o de cima entraria sem ninguém ter rodado teste nele.

Tirei o filtro de branch de destino. Os três checks agora rodam aqui e passaram.

@janeiaraujo
janeiaraujo merged commit b4db5de into feat/i18n-telas-secundarias Aug 3, 2026
3 checks passed
janeiaraujo added a commit that referenced this pull request Aug 3, 2026
perf: trazer o code splitting para a main (o #38 não chegou lá)
@janeiaraujo
janeiaraujo deleted the perf/code-splitting branch August 3, 2026 23:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants