Changelog - 12/07/2026
Semana de 06/07 a 12/07, na branch main-7k do front-web-base. É a semana em que o programa de performance/streaming da plataforma sai do papel: 93 commits filtrados, a maioria concentrada num único eixo.
Semana 06–12/07 — streaming SSR e clientLoader em toda a aplicação
- App-shell streaming SSR, começando pela home (
90d1dcfb4): oentry.serverpassa a transmitir o stream no shell-ready viaTransformStream— head processado no primeiro flush (tailwind inline, strip demodulepreloadcom keep-list derivada do manifest, strip de preloads de imagem não-LCP) e body em passthrough com tail-carry. Antes o stream era bufferizado até o fim pra rodar regex no HTML completo, ou seja, o primeiro byte esperava todo o conteúdo. Junto vem o piloto de deferred data na home:catalog,gameStatsCache,topWinselastWinssaem do caminho crítico e streamam viaSuspense/<Await>no documento SSR e via turbo-stream nas navegações.data, comSectionSkeletonno lugar. Continuam awaitedhomeRows,brand,authe a page description (meta/SEO/LCP). Cada perna deferida ganhou.catch(() => vazio), então rejeição degrada pra row vazia em vez de 500 na home inteira.streamTimeoutde 10s com abort combinado. - Estendido pra game page, hubs e navegação (
85a108c2d): o loader da página de jogo cai de 3 gates sequenciais pra 2 awaits (gameebrand, o mínimo pro meta/SEO), deferindostats,winners,related,providers,voteStatee as seções showcase. OgetStatsRaw, um endpoint do BFF não cacheado que só alimentava o DevPanel, foi movido pro gate de dev — produção deixa de pagar por ele. Nos hubs de cassino e ao-vivo,gameStatsCachee os wins passam a deferidos no caminho de rows. E em_layout.shouldRevalidate, troca de pathname deixa de revalidar o layout, o que remove a chamada de auth por usuário — transatlântica — do caminho crítico de toda navegação SPA logada; login e logout seguem revalidando viarevalidate()explícito. Skeletons CLS-zero novos:WinsCombinedSkeleton(o fallback anterior causava ~137px de shift no desktop),WinsMarqueeRowSkeleton,PaidTodaySkeleton,ListWinsSkeletoneGameRowSkeletonderivado dogameCardConfig, com widths corretos por breakpoint e por brand. clientLoaderdeixa a navegação game → game instantânea (1812d8b07): a navegação SPA pra/cassino/jogar/:provider/:gameesperava o.datainicial, que aguarda ogetDetail(round-trip de 0,5-1,5s em cache miss), travando a troca de rota inteira. OclientLoaderdevolve oloaderDatana hora —serverLoader()disparado semawait, cada campo encadeado como promise — então a URL troca instantaneamente e o conteúdo preenche por streaming.game,frontDescription,seoefaqEntryforam combinados num único boundary deAwaitValuecujo fallback reserva a geometria exata do conteúdo real, eslug/showcaseficam síncronos porque são deriváveis deparams/featuresConfigsem round-trip.5c24a1354acrescenta o skeleton pixel-perfect e o seed otimista do card clicado.- Padrão propagado pro resto das rotas —
b3e8c151d(hubs cassino e ao-vivo),bb0b2c012(categorias e provedores),f241a9145(home, incluindo seed otimista a partir dohomeRowsjá cacheado na store e o bundle de favoritos/recentes virando um únicofavoritesBundlestreamado),761088aa6(VIP e gamificação) ee6fe562f1(conteúdo WP, legal e busca, comlegalTermsdeferido).cc237adfccentraliza o preview de dev-skeleton num módulo único e removível;49ef0d808ed8401122bcorrigem imports.serverque vazaram pro caminho client. - Dois defeitos reais achados e corrigidos no próprio programa.
885f0e92c: o encoder de single-fetch do React Router corre toda promise deferida contra ostreamTimeout, e perna pendente virava frameE:["Unexpected Server Error"]dentro de um body 200, por fora do.catchdo loader; pior,errorElement={null}é falsy, então o<Await>re-lançava proErrorBoundaryda rota em vez de suprimir (a tela renderizava e depois virava erro); e o worker cacheava o.data200 com o frame de erro embutido por 60s, servindo o mesmo erro em HITs subsequentes. Fix:errorElementtruthy (fragment vazio) emAwaitValue/AwaitWinse na home.afc20a73d, resultado de revisão adversarial: obuildSpaShellbufferizava o stream inteiro pro usuário logado (TTFB = render completo, ~11s no pior caso) e devolvia um shell morto;Set-Cookiede tracking bloqueava o cache compartilhado pra todo visitante anônimo frio; o cache autenticado não tinha guard contra payload envenenado ou documento truncado; e a home resuspendia pra skeleton genérico em todo login/logout. ObuildSpaShellfoi removido e o autenticado em rota pública passa a receber a mesma stream real do anônimo. - Navegação e stats estáveis na página de jogo (
dfad863b1):getStatsegetVoteCountganham timeout fail-fast de 1200ms, com a promise original registrada nowaitUntil— assim o warming completa em background mesmo em cold-miss, o que o timeout sozinho mataria. As duas ondas sequenciais dePromise.alldo loader foram fundidas, removendo um round-trip serial.