Do lab ao CI: Lighthouse CI

TL;DR

Rodar o Lighthouse à mão pega problemas depois que já entraram. O Lighthouse CI (LHCI) move essa auditoria para dentro do pipeline: a cada pull request, ele carrega a build, roda o Lighthouse algumas vezes, e compara o resultado com regras (assertions) — reprovando o PR se a performance caiu. É a diferença entre descobrir uma regressão em produção e impedi-la de ser mergeada. O fluxo típico: lhci autorun (collect → assert → upload) num GitHub Action, com um lighthouserc definindo os limites. Transforma performance de “alguém lembra de checar” em portão automático.

O problema: a auditoria manual sempre chega tarde

No Galho 1 você aprendeu a rodar o Lighthouse (G1 nota 04) e a definir budgets (G1 nota 08). Mas uma auditoria manual tem um furo fatal: ela depende de alguém lembrar de rodá-la, e sempre acontece depois que o código já foi escrito, revisado e, muitas vezes, mergeado. Quando você descobre que o LCP piorou, a regressão já está na main — e rastrear qual dos vinte PRs da semana a causou é um pesadelo.

O problema real não é medir; é medir no momento certo. E o momento certo é antes do merge, automaticamente, em cada mudança. Isso é exatamente o que o CI já faz por testes e lint — e o Lighthouse CI estende para performance.

O que é o Lighthouse CI

O Lighthouse CI (LHCI) é a ferramenta oficial do Google para rodar o Lighthouse dentro de um pipeline de integração contínua. Ele orquestra três etapas, resumidas no comando lhci autorun:


graph LR
    A[PR aberto] --> B["collect<br/>build + roda Lighthouse Nx"]
    B --> C["assert<br/>compara com as regras"]
    C -->|passou| D["upload<br/>guarda histórico"]
    C -->|falhou| E[❌ PR bloqueado]
    style B fill:#4A90D9,color:#fff
    style C fill:#4A90D9,color:#fff
    style E fill:#D0021B,color:#fff
  • collect: sobe a aplicação (uma build de produção ou um servidor estático) e roda o Lighthouse várias vezes na(s) URL(s) escolhida(s). Rodar N vezes e pegar a mediana combate o ruído do lab (lembre de G1 nota 03: uma execução só é uma amostra barulhenta).
  • assert: compara os resultados com um conjunto de regras e retorna código de erro se alguma falhar — é o que faz o PR passar ou não.
  • upload: guarda os relatórios (num servidor LHCI, no Temporary Public Storage, ou num artefato) para você ver a tendência ao longo do tempo e comparar PRs.

Configuração mínima

Duas peças: um arquivo de config e um passo no CI. O lighthouserc.js (ou .json) define o que rodar e o que exigir:

// lighthouserc.js
module.exports = {
  ci: {
    collect: {
      staticDistDir: './dist',   // ou startServerCommand para um app dinâmico
      url: ['http://localhost/', 'http://localhost/produto'],
      numberOfRuns: 3,           // mediana de 3 execuções
    },
    assert: {
      assertions: {
        'categories:performance': ['error', { minScore: 0.9 }],
        'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
        'total-blocking-time': ['warn', { maxNumericValue: 200 }],
        'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
      },
    },
    upload: { target: 'temporary-public-storage' },
  },
};

E o passo no pipeline (exemplo GitHub Actions):

- name: Lighthouse CI
  run: |
    npm install -g @lhci/cli
    lhci autorun

Repare que os limites do assert são os mesmos Core Web Vitals do Galho 1 (LCP ≤ 2500 ms, CLS ≤ 0,1), agora como contrato executável. Cada assertion tem um nível: error (falha o build) ou warn (só avisa).

Rodar LHCI uma vez por PR e confiar no número absoluto

O que acontece: o build falha aleatoriamente (“flaky”) ou passa uma regressão real, porque o score oscilou entre execuções. Por quê: o lab é ruidoso — uma única execução varia com a carga da máquina de CI. Um número absoluto de uma corrida não é confiável. Como evitar: use numberOfRuns: 3 (ou mais) e a mediana; rode num ambiente de CI estável; e, quando possível, prefira assertions relativas (comparar com a base da main) a limites absolutos, que dão margem ao ruído do runner.

Lighthouse CI em uma frase: ele roda o Lighthouse automaticamente em cada PR (collect → assert → upload), comparando o resultado com regras que falham o build quando a performance regride — movendo a auditoria do “depois, se alguém lembrar” para “antes do merge, sempre”.

Como explicar em inglês

“Manual audits always catch problems too late — after the regression is already merged. Lighthouse CI moves the audit into the pipeline: on every pull request it builds the app, runs Lighthouse a few times, and checks the results against assertions — failing the PR if performance dropped. The flow is lhci autorun: collect, assert, upload. I run it three times and take the median to beat lab noise, and I assert on the same Core Web Vitals thresholds — LCP under 2.5s, CLS under 0.1. It’s lab data, so it doesn’t replace RUM — LHCI prevents regressions in CI, RUM confirms reality in the field. You need both.”

PTEN
Integração contínuaContinuous integration (CI)
PipelinePipeline
Regra / asserçãoAssertion
Falhar o buildFail the build
Instável (teste)Flaky
Portão / gateGate

O que vem a seguir

O LHCI já reprova PRs por métricas de performance. Mas há um tipo de budget que é ainda mais barato e imediato de checar — o tamanho do bundle — e vale a pena entender como combinar budgets de quantidade e de métrica num gate coerente que realmente segura a regressão.

Fontes