← skill tree

Capstone · Performance & rendering

Capstone: "Ticker" — painel de mercado em tempo real com 100k linhas (Angular 21, zoneless)

Capstone "Ticker": painel de mercado ao vivo com 100k+ linhas em Angular 21 zoneless que força junto OnPush/signals granulares, virtual scroll, Web Worker off-main-thread, SSR+hydration+@defer, análise de bundle e budgets/CWV no CI — cada ganho provado por número antes/depois, anti-tutorial-hell por construção.

▶ Demo funcional ao vivo

→ Abrir o Ticker (100k instrumentos, preços ao vivo)
Referência construída do que "pronto" significa: 60fps, ~25 linhas no DOM de 100k, ~15k updates/s via Web Worker, com HUD de performance. É o teu alvo — agora constrói a tua versão em Angular 21.

🎯 O que você constrói

Você constrói uma única feature real: um painel de cotações ao vivo — 100.000+ instrumentos (ações/cripto), busca e filtro instantâneos, uma tabela virtualizada que atualiza de preços por WebSocket, e um bloco de gráficos que só carrega quando entra em viewport. Pequeno para um fim de semana, denso o bastante para portfólio.

Essa feature é o pretexto perfeito porque cada gargalo de performance aparece naturalmente — você não "estuda" os tópicos, você bate de frente com eles:

  • Change detection / zoneless: preços mudam 20×/s. Com Zone.js isso é morte por CD global. Você roda provideZonelessChangeDetection(), estado 100% em signal()/computed(), tudo OnPush, e prova que só as células que mudaram re-renderizam.
  • Virtualização: 100k linhas no DOM = travamento. CDK virtual scroll + @for track por id estável forçam DOM recycling. Aqui você sente por que track errado destrói o ganho.
  • Off-main-thread: filtrar/ordenar/agregar 100k itens na main thread trava o input (INP alto). Web Worker faz o número; a UI só recebe o resultado. requestIdleCallback + debounce na busca evitam layout thrash.
  • Rendering strategy: SSR com hydration (não-destrutiva) para LCP baixo do shell; @defer como "islands" para o pacote de gráficos; streaming SSR para o TTFB.
  • Bundle & splitting: a lib de charts é pesada — ela nunca entra no bundle inicial. source-map-explorer prova onde o peso está; budgets no CI impedem regressão.
  • Core Web Vitals: você mede LCP/INP/CLS de verdade (lab + RUM com web-vitals) e trava orçamento no pipeline.

O fio condutor: tornar visível o invisível. Todo ganho de perf tem que ser medido antes/depois, não sentido "no olho".

Critérios de pronto
Passos sugeridos

Ordem incremental — cada passo entrega algo medível e prepara o próximo. Meça no fim de cada um.

  1. Baseline ruim de propósito. Gere as 100k linhas mock, renderize com @for sem virtual scroll, Zone.js ligado, filtro síncrono na main thread. Rode Lighthouse e Performance panel. Anote os números horríveis — esse é seu ponto de comparação. Sem baseline, nada do resto tem prova.
  2. Vá zeless + OnPush. Remova zone.js, adote provideZonelessChangeDetection(), migre estado para signals, marque tudo OnPush. Meça INP e o custo de CD. Aqui você entende por que CheckAlways não escala com stream de alta frequência.
  3. Virtualize. Troque a lista por CDK virtual scroll (ou windowing manual pra sentir o mecanismo). Corrija o track. Compare DOM node count e fps antes/depois.
  4. Empurre o trabalho pro worker. Mova filter/sort/aggregate para um Web Worker (Angular CLI gera com ng generate web-worker). Debounce a busca; use requestIdleCallback para o que não é urgente. Prove no Performance panel que a main thread respira durante a digitação.
  5. Ligue o real-time. WebSocket (ou mock com interval) atualizando preços. Atualize por signal granular — só a célula do preço, não a linha, não a tabela. Observe o CD com Angular DevTools profiler.
  6. SSR + hydration + @defer. Adicione SSR, hydration não-destrutiva, e isole os gráficos atrás de @defer (on viewport). Meça LCP e TTFB; experimente streaming SSR e compare.
  7. Ataque o bundle. source-map-explorer no build de prod. Ache o peso morto, garanta que charts está em chunk lazy, elimine duplicação. Commit do relatório de chunks.
  8. Trave tudo no CI. Configure budgets no angular.json (ou bundlesize) + Lighthouse-CI com asserts de LCP/INP/CLS. Faça uma PR que estoura o budget de propósito e mostre o CI vermelho.
  9. RUM. Instrumente web-vitals, mande as métricas pra um endpoint (ou log). Feche o README com a tabela antes/depois.
Rubrica de arquitetura
← voltar ao skill treefio de evolução · projeto integrador