Frontends com Vibecoding · Capítulo 21 de 33 · 30 min
Validar desempenho, autenticação e segurança
Carga, estado de erro e permissão passam a ter orçamento e teste, com toda chave fora do navegador e a checagem feita na função que lê o banco.
Este capítulo faz parte do curso gratuito Frontends com Vibecoding.
Uma imagem grande no topo da página costuma ser o vilão do LCP, o sinal que mede quando o maior bloco da tela aparece. O alvo é 2,5 segundos ou menos, com o limiar incluído.
A página lenta perde o cliente antes de carregar, porque ele volta para o resultado de busca e clica no concorrente. Core Web Vitals são os três sinais públicos que dizem se a tela parece rápida para quem está do outro lado.
Cada um dos três tem um vilão típico, e você mede todos com um número só. Com esse número na mão, o pedido ao agente deixa de ser opinião. O orçamento de desempenho entra desde o primeiro sprint, ou seja, o ciclo de uma ou duas semanas de trabalho.
O CLS mede o quanto a página pula sozinha enquanto carrega, com alvo de 0,1 ou menos. O vilão é imagem ou anúncio sem altura reservada, que empurra o botão no instante do clique e faz o cliente tocar no lugar errado.
Já o INP mede o tempo entre o toque e a resposta da tela, como o garçom que demora a olhar para a mesa. O alvo é 200 milissegundos ou menos, e o vilão é uma rotina longa em JavaScript segurando o navegador. Nos três, a página que fica exatamente no número entra na faixa boa.
Os três números valem pelo percentil 75 das visitas, separados entre celular e computador. A média esconde a experiência mais lenta, que costuma ser a do cliente no celular antigo, na rua.
O Lighthouse, o auditor embutido no navegador, simula uma carga e ajuda a diagnosticar LCP, CLS e travamento. Ele não mede o INP das visitas reais, por isso serve de diagnóstico e nunca de nota final.
No Search Console, o relatório lê os dados de campo numa janela móvel de 28 dias. Ele só aprova a página quando os três sinais ficam na faixa boa. A janela pertence ao conjunto de dados, e não à definição do limiar.
O Lighthouse CI roda a mesma auditoria a cada publicação e reprova o envio que estoura o alvo. A biblioteca web-vitals, o pacote que mede os três sinais no aparelho do visitante, envia os resultados ao painel.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Um orçamento de desempenho (o teto de peso e tempo que a página não pode passar, como o limite do cartão) entra no primeiro sprint. Produto visual sem esse controle degrada em silêncio: cada componente novo soma alguns quilobytes, ninguém mede, e meses depois o site está lento sem um culpado.
Dois instrumentos acompanham o orçamento. O profiling (a gravação de onde o navegador gasta cada milissegundo) aponta a rotina longa por trás do INP. O OpenTelemetry (o padrão aberto para coletar métricas, traces e logs) mostra a mesma lentidão do lado do servidor. Sem os dois, o Lighthouse diz que está lento e ninguém sabe onde.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Imagem tem teto de 150 KB no tamanho em que aparece na tela, em AVIF antes de WebP antes de formato legado. A conversão sai no build, via Sharp ou Squoosh. Uma foto de câmera com vários megabytes no topo da página estoura o orçamento sozinha, o vilão do LCP em quase todo site pequeno.
Fonte variável é o piso: um arquivo só substitui de seis a 12 arquivos estáticos, e o visitante baixa menos. Ela fica hospedada no seu próprio site, com Fontsource e subsetting, ou seja, o recorte que deixa só os caracteres usados.
A razão vem de um tribunal: a sentença de Munique tratou o envio do IP do visitante ao Google Fonts como vazamento de dado pessoal. Em documento confidencial, como um relatório para o conselho, fonte remota é anti-padrão, porque cada abertura avisa a um terceiro que aquele arquivo foi lido.
A conversão no build cabe num script curto, e o resultado vira um manifesto: a lista em JSON de cada variante, com formato, largura, altura e bytes. Com essa lista, o elemento picture declara as versões em AVIF e em WebP. O atributo sizes avisa quanto espaço a imagem ocupa na tela, em pixels de CSS.
O navegador multiplica esse espaço pela densidade de pixels do aparelho e baixa a menor variante que ainda cabe. O laboratório abaixo repete essa conta diante de você. A foto de abertura do curso, um JPEG de 1920 px, virou variantes de 480, 960 e 1440 px, cada uma medida contra o teto de 150 KB.
Escolher a variante certa da imagem e conferir o teto de 150 KB
Arraste a largura da tela simulada, troque a densidade entre 1x e 2x e veja qual arquivo o navegador escolhe, quanto ele pesa e se cabe no orçamento.
A demonstração monta um elemento picture real com a foto de abertura do curso em AVIF e em WebP, nas larguras de 480, 960 e 1440 px, e o JPEG original como reserva. Um deslizante simula a largura da tela e mostra a variante que o navegador escolheria, com os bytes dela, a comparação com o JPEG e o selo do teto de 150 KB em texto. Uma tabela lista todas as variantes geradas no build e a linha do SVG minificado pelo svgo, com o viewBox preservado.
A demonstração interativa carrega quando este trecho entra na tela.
O orçamento de desempenho do primeiro sprint
| Item | Teto | Quem mede | Vilão típico |
|---|---|---|---|
| LCP | 2,5 s ou menos no percentil 75 | Lighthouse CI e web-vitals | Imagem grande no topo |
| CLS | 0,1 ou menos no percentil 75 | Lighthouse CI e web-vitals | Imagem sem altura reservada |
| INP | 200 ms ou menos no percentil 75 | web-vitals no aparelho real e profiling | Rotina longa em JavaScript |
| Imagem | 150 KB no tamanho exibido, AVIF antes de WebP | Sharp ou Squoosh no build | Foto de câmera sem conversão |
| Fonte | Um arquivo variável, hospedado no site | Fontsource com subsetting | Chamada remota ao Google Fonts |
| Servidor | Tempo de resposta acompanhado por rota | OpenTelemetry | Consulta lenta que ninguém vê |
Cada linha vira uma reprovação automática na esteira quando o número estoura; sem a linha escrita, o teto é opinião.
Numa padaria, o cardápio publicado direto da câmera do celular, em oito megapixels, vira sozinho o maior contribuinte do LCP. O cliente com internet de rua desiste antes de ver o prato, e a venda some sem deixar rastro.
Corrigir é converter para AVIF e redimensionar, sem trocar de fornecedor nem refazer o site. Com o teto de 150 KB escrito, a foto seguinte já nasce no tamanho certo.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Rode o Lighthouse no modo celular com rede simulada e anote os itens na ordem de impacto. Peça ao agente a correção na raiz de cada um: imagem em AVIF abaixo de 150 KB, altura reservada, script pesado adiado e fonte variável hospedada com Fontsource.
Escreva os seis tetos como regra de reprovação automática no Lighthouse CI. Só aprove a publicação quando LCP, CLS e INP ficarem dentro do alvo no percentil 75.
Proteger dados, chaves e permissões antes de o site ir ao ar
O orçamento de desempenho protege quem já entrou na página, e o texto vindo de fora, a chave no navegador e a permissão do banco continuam abertos.
A GitGuardian contou 28,65 milhões de novos segredos escritos direto no código de repositórios públicos em 2025, 34% acima do ano anterior. Boa parte nasce de um pedido simples ao agente: conectar direto numa API externa, o caminho mais curto para o pedido funcionar.
Uma API é a porta de entrada de um serviço de fora, e a chave é a senha dessa porta. Quando a chave viaja dentro da página, qualquer visitante a copia e gasta na sua conta.
Três defesas só valem no servidor: limpar o texto que um estranho digita, guardar a chave dos serviços externos e conferir quem pode ver o quê. Cada uma se testa em minutos, e a dependência desatualizada anula as três quando carrega uma falha já pública.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Um levantamento da Veracode mediu duas coisas ao mesmo tempo, em mais de 150 modelos. O código gerado por IA compila e roda em mais de 95% dos casos, e a aprovação em segurança fica em 55%. Ela cai para 15% na injeção de conteúdo malicioso, a falha que nasce no formulário de comentário.
A comparação de dois anos do mesmo levantamento fecha a porta ao atalho: modelos mais novos melhoraram sintaxe sem melhorar a segurança. Trocar de modelo não conserta essa classe de falha, e a revisão continua sendo sua.
O React (a biblioteca que monta a tela a partir do seu código) escapa texto por padrão: uma tag script digitada no comentário aparece inerte, como texto puro. A brecha abre quando o código usa dangerouslySetInnerHTML, que injeta HTML cru, ou funções como eval e document.write.
A correção é limpar esse texto com uma biblioteca madura, como o DOMPurify no navegador ou o sanitize-html no servidor, na hora de gravar. Limpar na gravação passa por um ponto único, e toda tela que mostrar aquele conteúdo, mesmo a que ainda não foi escrita, já recebe o texto limpo.
Já a sessão fica num cookie httpOnly, ou seja, o crachá que só o servidor lê. Fora dele está o localStorage, a gaveta que qualquer script da página abre, e essa escolha decide o tamanho do estrago quando a limpeza falha.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
No Next.js (a estrutura que organiza o site em React, com páginas e rotas de servidor), a variável com prefixo NEXT_PUBLIC_ vai dentro do pacote enviado ao navegador. É assim que a chave escapa. Pedir ao agente para conectar direto numa API externa produz esse vazamento, porque é o caminho mais curto.
O conserto é uma rota do próprio servidor, como /api/clima: o componente chama a rota, e o servidor usa a chave para falar com o serviço externo. Chave exposta uma vez só se conserta gerando outra no provedor.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Esconder um botão no menu é experiência de uso, e a barreira fica em outro lugar: qualquer pessoa chama a mesma rota pelo terminal, sem passar pela tela. A permissão precisa ser conferida de novo dentro da função que lê ou grava no banco.
O teste mais simples prova isso: troque o identificador na URL da página e veja se aparece o dado de outra pessoa. Se aparecer, a checagem só existe na tela, e um cliente curioso lê a fatura do vizinho.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Dependência tem patch de segurança (a correção que o autor da biblioteca publica) com data, e a lista do seu projeto envelhece sozinha. Uma CVE é o registro público de uma falha de segurança, com número e data, como um recall de carro.
O React corrigiu a CVE-2025-55182, que afeta as versões 19.0.0 a 19.2.2, e quem ficou nelas carrega uma falha que qualquer atacante conhece.
Vale o mesmo para quem gera PDF de HTML: o WeasyPrint 69 é obrigatório para quem renderiza HTML não confiável, por causa da CVE-2026-49452. O jsPDF 4.2.1 corrigiu um path traversal (a leitura de arquivo fora da pasta permitida) no build Node. O pdfMake 0.3.11 ganhou setUrlAccessPolicy() contra download de recurso controlado por atacante.
Antes de renderizar HTML de terceiro, o conteúdo passa por sanitize-html. O renderizador roda num sandbox (uma caixa isolada da rede interna) que barra o SSRF, o pedido forjado que usa o seu servidor para alcançar um endereço interno.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
No Astro 6, o gerador de sites estáticos, a CSP já vem embutida na configuração. Ela é a política que lista de onde o site aceita script, como a portaria que só deixa subir quem está na lista de convidados.
Num escritório de contabilidade que gera o balanço em PDF, o HTML enviado pelo cliente passa por sanitize-html. Só depois ele vai para o renderizador atualizado. Trocar o id do cliente na URL do portal abre o balanço de outra empresa quando a checagem mora só no menu.
Procure dangerouslySetInnerHTML e toda variável com o prefixo NEXT_PUBLIC_ antes de aprovar a próxima entrega. Mova a chamada para uma rota do servidor e confira se a sessão está em cookie httpOnly.
Rode npm audit. Suba o React para fora da faixa 19.0.0 a 19.2.2, o WeasyPrint para a 69, o jsPDF para a 4.2.1 e o pdfMake para a 0.3.11. Só publique quando a auditoria terminar sem vulnerabilidade alta ou crítica conhecida.
Guia prático: Core Web Vitals da landing page com visita real
O Lighthouse diagnostica antes de publicar; a nota que vale vem de quem visitou. Para página de campanha, que vive poucas semanas, esperar o relatório do Search Console costuma chegar tarde. O Speed Insights da Vercel mostra o percentil 75 das visitas reais desde o primeiro dia de tráfego, na prévia e em produção.
Desde 25 de agosto de 2026 ele tem camada gratuita em todos os planos: 10 mil eventos por equipe numa janela móvel de 30 dias, com o Real Experience Score, a nota que resume a experiência. LCP, INP e CLS separados, as rotas ruins e o elemento responsável pedem o Speed Insights Plus, a 10 dólares por projeto ao mês no plano Pro, mais os eventos. Ao estourar o limite gratuito, a coleta pausa por pelo menos 14 dias.
Atualização de segurança: o Next.js publicou em 30 de setembro de 2026 as versões 16.3.8 e 15.5.27. Uma das correções, de severidade alta, afeta a otimização de imagens de quem configurou images.remotePatterns.

Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Dona de uma loja virtual de cosméticos, com landing page de pré-venda anunciada no Instagram
Varejo online, campanha de lançamento
Dor
A página tinha nota alta no Lighthouse do computador. No celular, o banner de frete carregava depois e empurrava o botão de compra no instante do toque.
Solução
Ela instalou o Speed Insights, filtrou por celular e viu a rota da campanha fora do grupo ótimo. Pediu ao agente altura reservada para o banner, a foto do topo em AVIF com prioridade e a etiqueta de anúncios carregada depois da hidratação.
Resultado
A rota voltou ao grupo ótimo na leitura de sete dias, e o toque no botão deixou de cair no banner. O efeito em vendas ficou para o teste A/B.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Medir e corrigir a landing page com dado de visita real
Seis passos. O laboratório aponta o suspeito; a visita real diz se o cliente sentiu.
Passo 1: Atualize o Next.js antes de medir
npm install next@16.3.8 (ou next@15.5.27 na linha 15) e rode o verify do capítulo "Planejar a modernização e publicar com reversão".
Deu certo quando: O build passa e a página de campanha abre na prévia com a versão nova.
Erro comum: Medir desempenho numa versão com falha de segurança aberta e ter de refazer a medição depois.
Passo 2: Instale o Speed Insights
npm i @vercel/speed-insights e o componente SpeedInsights, importado de @vercel/speed-insights/next, dentro do body do layout raiz. Publique.
Deu certo quando: O script do Speed Insights aparece no código da página publicada e o painel começa a receber eventos.
Erro comum: Instalar só em produção e não ver a regressão que já estava na prévia.
Passo 3: Leia pelo celular, no percentil 75
No painel, troque para Mobile, escolha o ambiente e abra a rota da campanha. A média esconde o aparelho antigo na rede da rua.
Deu certo quando: Você sabe em qual grupo a rota está e qual métrica puxa a nota para baixo.
Erro comum: Comemorar a nota do computador, que quase sempre é boa.
Passo 4: Ache o suspeito no Lighthouse em modo celular
Com rede simulada, anote o elemento do LCP, os saltos de layout e as tarefas longas no clique do formulário.
Deu certo quando: Uma lista de três itens em ordem de impacto, cada um com o elemento nomeado.
Erro comum: Pedir ao agente para melhorar o desempenho sem dizer qual elemento e qual métrica.
Passo 5: Corrija na raiz, um item por pedido
Foto do topo em AVIF abaixo de 150 KB com prioridade; altura reservada em banner, logotipo e vídeo; etiquetas de terceiros depois da hidratação; validação no blur, não a cada tecla.
Deu certo quando: Cada pedido volta com um diff pequeno e a medição de laboratório do item corrigido.
Erro comum: Três correções num pedido só, sem saber qual delas resolveu.
Passo 6: Confirme no campo e vigie o limite
Releia o painel depois de alguns dias de tráfego. Em campanha com muito clique, reduza a taxa de amostragem do pacote para não esgotar os 10 mil eventos gratuitos.
Deu certo quando: A rota aparece no grupo ótimo no celular e a coleta segue ativa.
Erro comum: Estourar o limite na primeira semana e ficar 14 dias sem dado, justo no pico da campanha.
No fim você tem: Uma landing page com Next.js atualizado, medição de visita real desde a prévia e as três correções de maior impacto confirmadas no celular.
Guia prático: o peso que não aparece e a chave que não vai para o chat
O arquivo de dependências mostra só parte do que a página carrega. Na biblioteca de 1.451 componentes estudada em 07/10/2026, 319 usam WebGL, shader (o programa que desenha direto na placa de vídeo) ou biblioteca 3D, 22% do acervo. Desses, 245 não declaram dependência nenhuma, porque o shader está escrito dentro do próprio componente. Entre os heróis, 220 de 515 são assim. Nos templates, o site com Three.js saiu com 658 kB de JavaScript (179 kB comprimidos); um site parecido sem 3D, com 206 kB (62 kB).
O mesmo vale para o que chega por endereço externo. Cinco templates carregam o Tailwind por CDN, que a própria documentação diz ser só para desenvolvimento, e seis puxam scripts de CDN de terceiros. Arquivo de outro servidor pode mudar ou sumir; se ficar, fixe a versão e use o atributo integrity, que faz o navegador recusar o arquivo alterado.
A chave de API é o outro peso invisível. O curso estudado ensina um gesto simples: o agente cria o arquivo .env, abre esse arquivo no editor do computador para a pessoa colar a chave, e depois confere se ela está lá sem mostrar o valor. A chave nunca passa pelo chat. Quem tem a sua chave gasta o seu saldo.
Crie o arquivo .env na pasta [PASTA DO PROJETO] com a linha [NOME_DA_CHAVE]=
e abra esse arquivo no editor de texto do meu computador.
Eu colo a chave depois do sinal de igual e salvo.
Não me peça a chave aqui na conversa.
Quando eu disser "salvei":
1. Confira se a linha tem valor, sem exibir o valor.
2. Confirme que .env está no .gitignore.
3. Mostre onde o código lê a chave e garanta que é só no servidor.Medir o peso escondido e guardar a chave fora da conversa
Cinco passos para antes de aceitar um componente bonito ou ligar um serviço pago.
Passo 1: Pergunte o que o componente desenha e como
Antes de colar um fundo ou herói animado, peça ao agente para dizer se ele usa canvas, WebGL ou shader, mesmo sem pacote novo. O peso real está no código, não na lista de dependências.
Deu certo quando: Você sabe se o componente desenha na placa de vídeo e quanto código ele soma.
Erro comum: Olhar o package.json, não ver nada novo e concluir que o componente é leve.
Passo 2: Meça o pacote antes e depois
Rode o build antes de colar o componente e depois. Compare o JavaScript comprimido. Se o salto não cabe no orçamento, peça uma versão em CSS ou uma imagem parada no lugar.
Deu certo quando: O aumento está anotado e cabe no orçamento do projeto.
Erro comum: Medir só na sua máquina rápida, onde o efeito parece de graça.
Passo 3: Traga para o projeto o que vem de CDN
Script e estilo de terceiros em produção viram arquivo local ou ficam com versão exata e integrity. Tailwind por CDN sai e entra pelo build.
Deu certo quando: Nenhum script externo sem versão fixa e sem integrity.
Erro comum: Deixar o link sem versão e descobrir a mudança pelo site quebrado.
Passo 4: Guarde a chave no .env sem passar pelo chat
Use o pedido do bloco de código. A chave é colada por você no editor, nunca na conversa, e o agente confere a presença sem exibir o valor.
Deu certo quando: A chave está no .env, o .env está no .gitignore e nenhuma mensagem da conversa contém a chave.
Erro comum: Colar a chave no chat "só desta vez"; ela fica no histórico da conversa.
Passo 5: Ponha limite de gasto no provedor
No painel do serviço, crie a chave só com a permissão que o projeto usa e defina limite de consumo quando houver. Se a chave vazar, troque no provedor; apagar o arquivo não resolve.
Deu certo quando: A chave tem permissão mínima e você sabe onde revogá-la.
Erro comum: Criar a chave com acesso total porque é mais rápido.
No fim você tem: Componentes com peso conhecido, terceiros sob controle e chaves que nunca passaram pela conversa com o agente.
Guia prático: a política de segurança de conteúdo, primeiro em modo de relatório
A aula apresentou a CSP (Content Security Policy, a lista de onde a página aceita script, estilo e conexão). Na página de campanha, o problema é ligar a política sem derrubar pixel, Analytics e checkout. Você sai com a política rodando primeiro em modo de relatório, que só avisa, e com o caminho para trocar a liberação genérica de script em linha por nonce, um número único por resposta.
Funções, casos de uso e aplicações
Funções
As peças da política de segurança de conteúdo
| Função ou recurso | O que faz | Quando usar | Referência |
|---|---|---|---|
| Content-Security-Policy-Report-Only | Aplica a política sem bloquear nada e relata cada violação | Antes de ligar a política para valer, por uma ou duas semanas de tráfego real | MDN, disponível em todos os navegadores desde agosto de 2016 |
| report-to e Reporting-Endpoints | Dizem para onde vão os relatórios; report-uri, a forma antiga, está sendo substituído | Junto com o modo de relatório; mantenha os dois na transição | MDN |
| nonce com 'strict-dynamic' | Só roda o script que traz o número da resposta, e os scripts que ele carregar | Quando 'unsafe-inline' não é aceitável; no Next.js exige renderização a cada pedido | Next.js 16.4, guia de CSP |
| Integridade de sub-recurso (experimental.sri) | Calcula no build o hash de cada script e mantém a página estática | Landing estática que quer política estrita sem renderizar a cada visita | Next.js 16.4, guia de CSP |
| object-src 'none' e base-uri | Bloqueiam plugin legado e a tag <base> injetada que desvia links relativos | Sempre que a página não usa objeto embutido | OWASP, CSP Cheat Sheet |
| 'wasm-unsafe-eval' | Libera só WebAssembly, sem reabrir o eval de JavaScript | Motor de física, decodificador ou editor que roda em WebAssembly | Next.js 16.4, guia de CSP |
CSP é uma camada a mais: o texto vindo de fora continua sendo limpo no servidor.
Casos de uso
Gestor técnico de uma agência de lançamentos digitais em Florianópolis
Marketing digital
Dor
Ligou uma CSP copiada de um tutorial na página de pré-venda e o pixel da Meta e o checkout em iframe pararam no dia do lançamento.
Solução
Voltou a política para Content-Security-Policy-Report-Only com um endpoint de relatório, rodou duas semanas, montou a lista de domínios pelos relatórios e só então trocou o cabeçalho para o que bloqueia.
Resultado
O que observar: relatórios de violação caindo a zero na última semana em modo relatório, e eventos do pixel no Gerenciador de Eventos no mesmo volume depois da troca.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Coordenador de TI de uma faculdade particular em Salvador
Educação
Dor
A página de inscrição do vestibular mostra o nome digitado na tela de confirmação, e um teste interno conseguiu rodar script por esse campo.
Solução
Além de limpar o texto no servidor, pediu política com nonce e 'strict-dynamic', object-src 'none' e base-uri 'self' nas rotas do formulário, que já eram renderizadas a cada pedido.
Resultado
O que observar: o mesmo teste de injeção bloqueado no console do navegador, com o relatório de violação chegando ao endpoint.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Na prática
Neste portal, a política fica em next.config.ts, dentro de headers(), e cada exceção traz o motivo e a data no comentário: 'wasm-unsafe-eval' entrou em 25/09/2026 para o motor de física do laboratório 3D, e worker-src 'self' blob: para os Web Workers que nascem de Blob. O próprio comentário registra a dívida: 'unsafe-inline' segue liberado por causa dos scripts do Tag Manager, com a migração para nonce anotada como pendente. O HSTS (o cabeçalho que obriga HTTPS) aparece no next.config.ts e no src/middleware.ts, e o teste middleware-hsts.test.ts reprova quando os dois divergem.
{
key: "Content-Security-Policy",
// CSP: 'unsafe-inline' mantido temporariamente por compatibilidade com GTM inline scripts.
// TODO: migrar para nonces (...) para eliminar 'unsafe-inline'.
// 'unsafe-eval' REMOVIDO — não é necessário para GTM/GA4 e representa risco de XSS.
// 'wasm-unsafe-eval' (25/09/2026): autoriza só WebAssembly.instantiate, sem reabrir
// eval() de JavaScript.
value: "default-src 'self'; worker-src 'self' blob:; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' https://www.googletagmanager.com ...; frame-ancestors 'self'",
},// proxy.ts — Next.js 16 (nas versões anteriores, middleware.ts)
import { NextRequest, NextResponse } from "next/server";
const MODO_RELATORIO = true; // troque para false depois de duas semanas limpas
export function proxy(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
const politica = [
"default-src 'self'",
"script-src 'self' 'nonce-" + nonce + "' 'strict-dynamic' https://www.googletagmanager.com",
"connect-src 'self' https://www.google-analytics.com",
"img-src 'self' data: https:",
"object-src 'none'",
"base-uri 'self'",
"frame-ancestors 'none'",
"report-to csp",
].join("; ");
const cabecalho = MODO_RELATORIO ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy";
const pedido = new Headers(request.headers);
pedido.set("x-nonce", nonce);
pedido.set("Content-Security-Policy", politica); // o Next.js lê o nonce daqui
const resposta = NextResponse.next({ request: { headers: pedido } });
resposta.headers.set(cabecalho, politica);
resposta.headers.set("Reporting-Endpoints", 'csp="https://campanha.exemplo.com.br/api/csp"');
return resposta;
}Da política copiada à política que não derruba a campanha
Passo 1: Liste o que a página carrega de fora
Abra a aba Rede do DevTools e anote os domínios de script, imagem, conexão e iframe: Analytics, pixel, checkout, vídeo.
Deu certo quando: Cada domínio da lista tem um dono e um motivo.
Passo 2: Suba a política em modo relatório
Use Content-Security-Policy-Report-Only com report-to. Nada é bloqueado; cada violação vira um relatório.
Erro comum: Pôr a política numa tag meta: o modo relatório só funciona como cabeçalho.
Passo 3: Por duas semanas, leia os relatórios
Agrupe por diretiva e domínio. Domínio legítimo entra na lista; o desconhecido vira investigação.
Passo 4: Nonce no lugar da liberação genérica
Com nonce e 'strict-dynamic', o script que você autorizou carrega os dele. Confira quais páginas passam a ser renderizadas a cada visita.
Deu certo quando: Nenhum 'unsafe-inline' em script-src.
Passo 5: Ligue para valer e mantenha o relatório
Troque o nome do cabeçalho e mantenha report-to. O relatório continua avisando quando alguém adicionar um script novo.
No fim você tem: A política bloqueia o script injetado sem calar o pixel, e cada exceção tem data e motivo.
Armadilhas
Política ligada sem relatório derruba o pixel
Rode a CSP em modo relatório antes de bloquear e anote o motivo de cada exceção.
- 'unsafe-inline' em script-src tira boa parte da proteção contra XSS
- Nonce no Next.js exige renderizar a página a cada pedido
- Sem report-to, o modo relatório não manda nada
- Dois lugares definindo o mesmo cabeçalho precisam de teste que compare
- CSP não substitui limpar o texto digitado no servidor
O teste: Abra o console da landing: aparece alguma violação que você não sabe explicar?
alexandrecaramaschi.com/educacao/frontends-com-vibecoding
Aplicar os recursos ao projeto
Segurança e desempenho pedem evidências diferentes
| Questão | Verificação | O que não conclui |
|---|---|---|
| HTML recebido | Política de sanitização | Não autoriza a operação |
| Tempo de resposta | Medição da tarefa | Não prova segurança |
| Requisição protegida | Permissão no servidor | Não depende do botão |
| Carga inicial | Arquivos e execução | Não resume toda a experiência |
Sanitização, autorização e medição de desempenho resolvem problemas diferentes e precisam ser verificadas no contexto em que o produto funciona.
DOMPurify tira do HTML de fora tudo o que pode virar ataque, antes de ele entrar na página. Esse trabalho se chama sanitização: reduzir o conteúdo ao que é permitido. Texto que saiu de um modelo de IA é conteúdo de terceiro, e conteúdo de terceiro passa pelo filtro.
No painel administrativo deste site, a resposta de Claude, Gemini e GPT virava HTML e ia direto para a tela, sem filtro nenhum. Agora esse HTML passa por DOMPurify.sanitize antes de aparecer. O que é formatação continua; atributo de evento e script somem no caminho.
Mande uma amostra com atributo de evento e confirme que ele sumiu e o texto ficou. Limpar o HTML não dá permissão nem protege segredo enviado ao navegador: valide também no serviço. Mantenha a biblioteca atualizada e uma política de segurança de conteúdo no lugar. Nenhuma saída de modelo entra na tela sem essa passagem.
Lighthouse roda uma bateria de exames de laboratório na página e devolve notas de velocidade e acessibilidade. Ele aponta onde procurar, como imagem pesada segurando a tela. Use para comparar antes e depois; laboratório não é o celular do seu cliente na rua.
Abra a versão publicada do catálogo, escolha celular e rode. Veja qual elemento demora mais a aparecer e o que atrasa a pintura da tela. Depois de reduzir uma imagem, rode de novo com a mesma configuração, senão a comparação não vale.
Compare os diagnósticos, e não a nota redonda que sobe e desce sozinha entre execuções. Repita três vezes antes de comemorar. Extensão do navegador e rede simulada mexem no resultado, e o exame de acessibilidade não testa o fluxo de compra com teclado.
Seu caderno neste capítulo
Abrir o caderno completoSelecione um trecho do capítulo para destacar ou anotar. Nos vídeos e áudios, use Anotar este momento. No teclado, selecione com Shift e as setas e use Alt+Shift+D para destacar ou Alt+Shift+N para anotar.
Salvo neste navegador. Entre na sua conta para levar o caderno a outros aparelhos.
Entre na sua conta para compartilhar o que aprendeu e convidar alguém para estudar com você.
Conexões deste capítulo
Veja o que estudar antes e para onde seguir depois, explore os conceitos e compare abordagens em outros cursos. Sugestões marcadas como “sugerido pelo grafo” vêm dos assuntos em comum, não do índice do curso.
Estude antes
- CursoClaude Code CLI: Programação com IA
- Destrave o que impede o robô de ler o sitesugerido pelo grafoApresenta os conceitos “LCP”, “CLS” e “CDN”, usados em “Validar desempenho, autenticação e segurança”.
- Mobile e performance: INP e Core Web Vitalssugerido pelo grafoApresenta o conceito “INP”, usado em “Validar desempenho, autenticação e segurança”.
- Introdução ao Next.jssugerido pelo grafoApresenta o conceito “Next.js”, usado em “Validar desempenho, autenticação e segurança”.
Depois, siga para
- CursoPrompt Engineering para Executivossugerido pelo grafo7 capítulos de “Prompt Engineering para Executivos” usam conceitos apresentados em “Frontends com Vibecoding”.
- CursoLLM FinOps: o custo da IA para quem assina o orçamentosugerido pelo grafo3 capítulos de “LLM FinOps: o custo da IA para quem assina o orçamento” usam conceitos apresentados em “Frontends com Vibecoding”.
Conceitos deste capítulo
O mesmo assunto em outros cursos
- SEO ProgramáticoTestar o template no pior caso e achar o tetoExaminar conexões de Testar o template no pior caso e achar o teto
- Software e IA para executivosMedir a velocidade que o cliente sente no celular deleExaminar conexões de Medir a velocidade que o cliente sente no celular dele
- MCP com Chrome: Automação com IAMedir carregamento sem mentir para o clienteExaminar conexões de Medir carregamento sem mentir para o cliente
- CRO: Otimização de Conversão e ExperimentaçãoMobile e performance: INP e Core Web VitalsExaminar conexões de Mobile e performance: INP e Core Web Vitals
Voltar ao capítulo anterior: Auditar acessibilidade e contraste nos dois temas
Leve uma ideia para a prática
Escolha uma atividade no painel e volte a este curso quando quiser.
Atividades e evolução ficam reunidas no painel da sua conta.
Laboratórios ao vivo deste curso
Cada laboratório monta a biblioteca real dentro da aula, com controles para você mexer e o código do exemplo para copiar. O texto de reserva descreve a demonstração para quem lê sem JavaScript. O link abre o capítulo já no ponto do laboratório.
Base UI
Prenda o foco num diálogo sem escrever o comportamento
Abra a janela Agendar visita, percorra os campos com Tab, feche com Esc e acompanhe no painel onde o foco está e para onde ele volta.
Pacote
Abrir no capítuloConstruir componentes, usar o registro e publicar o catálogo@base-ui/reactLucide e Iconify
Mantenha uma família de ícones coerente e nomeie cada botão
Mude tamanho, traço e cor da barra, veja o símbolo do Iconify acompanhar o Lucide e rode a auditoria de nomes acessíveis.
Pacote
Abrir no capítuloProjetar uma linguagem de ícones e ilustraçãolucide-react, @iconify/reactMotion
Testar os três sinais que autorizam o terceiro degrau
Reproduza a entrada em sequência, aperte o botão com mola e arraste o cartão; ajuste rigidez e amortecimento e veja o que muda.
Pacote
Abrir no capítuloProjetar movimento, assinatura e narrativas por rolagemmotionVidstack
Ver o que separa um player de um vídeo cru
Dê o play, troque a velocidade e ligue a legenda; o painel ao lado mostra o estado que o player publica e que a etiqueta crua esconde.
Pacote
Abrir no capítuloProjetar movimento, assinatura e narrativas por rolagem@vidstack/reactcmdk
Achar um destino entre quarenta digitando três letras
Abra a paleta, digite fat e escolha um item só pelo teclado; o painel embaixo conta o que o filtro deixou passar e quanto tempo levou.
Pacote
Abrir no capítuloConstruir formulários e estados de interaçãocmdknumber-flow
Animar indicadores que mudam ao vivo com formato pt-BR
Veja três indicadores fictícios rolarem a cada troca e compare com o número em texto puro. Pause, reinicie e observe o separador de milhar.
Pacote
Abrir no capítuloProjetar gráficos e painéis pela decisão@number-flow/reactApache ECharts
Medir o custo de desenhar 200 mil pontos com o ECharts
Troque o tipo de gráfico e o volume de pontos, leia o tempo de desenho e alterne o eixo em zero. Mude o tema do site e veja as cores refazerem.
Pacote
Abrir no capítuloProjetar gráficos e painéis pela decisãoechartssharp e svgo
Escolher a variante certa da imagem e conferir o teto de 150 KB
Arraste a largura da tela simulada, troque a densidade entre 1x e 2x e veja qual arquivo o navegador escolhe, quanto ele pesa e se cabe no orçamento.
Pacote
Abrir no capítuloValidar desempenho, autenticação e segurançasharp, svgoReact Flow (xyflow)
Disparar um pedido e ver o orquestrador distribuir, conferir e responder
Alterne paralelo e sequencial, ligue e desligue a verificação e use a medição real; observe o tempo de parede em cada combinação.
Pacote
Abrir no capítuloConstruir as cenas do orquestrador, do paralelismo e do robô@xyflow/reactGSAP, Web Workers e number-flow
Dividir mil tarefas entre trabalhadores reais e correr três ritmos de geração
Execute com um trabalhador, depois com quatro e oito, e compare o tempo; em seguida percorra a corrida e separe a espera inicial do ritmo.
Pacote
Abrir no capítuloConstruir as cenas do orquestrador, do paralelismo e do robôgsap, @number-flow/reactThree.js com React Three Fiber, drei, Rapier e XR
Carregar o braço robótico, ver a física trabalhar e entrar na cena com o visor
Carregue a cena pelo botão, inicie o ciclo, mostre os ângulos das juntas, troque a câmera e a velocidade; com visor, entre em realidade virtual.
Pacote
Abrir no capítuloConstruir as cenas do orquestrador, do paralelismo e do robôthree, @react-three/fiber, @react-three/drei, @react-three/rapier, @react-three/xrMotion
Ver quatro agentes em raias trocando mensagens e a revisão devolvendo um trecho
Reproduza os 60 s de modelo, percorra o tempo pelo controle e esconda as mensagens para comparar a leitura; repare no tempo de parede contra a soma.
Pacote
Abrir no capítuloEspecificar, medir e produzir as cenas da máquinamotionMediaRecorder, Canvas 2D e Long Animation Frames (plataforma)
Medir o quadro da cena e gravar seis segundos dela em vídeo
Suba as partículas, force um bloqueio de 300 ms e leia o medidor; depois grave seis segundos, veja o codec escolhido e baixe o arquivo.
Pacote
Abrir no capítuloEspecificar, medir e produzir as cenas da máquinasem pacotesigma.js, graphology com ForceAtlas2 e cosmos.gl
Ver o grafo real do curso e um grafo de milhares de nós se organizarem em aglomerados
Rode o layout no grafo real, passe o mouse pelos nós e busque uma entidade; troque para 20 mil nós e leia o medidor; depois carregue o modo massivo na placa de vídeo.
Pacote
Abrir no capítuloAnimar um grafo de conhecimento amplo em movimentosigma, graphology, graphology-layout-forceatlas2, graphology-generators, @cosmos.gl/graph
Capítulos vizinhos em Frontends com Vibecoding
- 19Avaliar busca, conversão e padrões de comércio
- 20Auditar acessibilidade e contraste nos dois temas
- 21Validar desempenho, autenticação e segurança
- 22Planejar a modernização e publicar com reversão
- 23Construir o projeto final, medir a cara de IA e revisar