3

Por que você não pode apagar CSS "não usado" buscando pelo nome da classe

Eu ia apagar um bloco de CSS que parecia morto. A busca dizia que várias classes não eram usadas em lugar nenhum, e a busca estava errada.

Eu fiz o MyIPScan, um conjunto de testes gratuitos de IP, DNS, WebRTC e vazamentos de VPN. Com o tempo, a folha de estilo cresceu e eu quis limpar o que parecia sobrar. O método óbvio: pegar cada classe do CSS, buscar no código e apagar o que não aparece. Não funcionou.

O que a busca não enxerga

Parte das classes do site não existe como texto em lugar nenhum do código. Elas são montadas em JavaScript a partir de um prefixo e de um slug:

// esboço ilustrativo, não é o código original
const key = route.slug;            // por exemplo "dns"
el.className = `per-route-status-${key}`;

No CSS existe .per-route-status-dns. No código, só existe per-route-status- e uma variável. Se você buscar per-route-status-dns, encontra zero resultados. A classe parece morta, mas pode aparecer na tela de quem abre aquela rota.

O tamanho do problema

Contei o que havia no projeto:

  • 486 nomes de classe estáticos, escritos por extenso;
  • 70 prefixos que viram classes quando juntados com algo em tempo de execução;
  • 2.506 slugs que podem completar esses prefixos.

Não dá para conferir isso no olho. E nenhuma ferramenta que só lê texto consegue saber quais combinações de prefixo e slug realmente acontecem.

Por que as ferramentas de "CSS não usado" erram aqui

Em geral, essas ferramentas funcionam de dois jeitos. Ou leem o código-fonte procurando o nome da classe, e aí caem no mesmo buraco da busca. Ou abrem páginas num navegador e anotam o que foi aplicado, e aí só veem as rotas e estados que você visitou. Um estado de erro que aparece uma vez por mês não está no relatório, e o CSS dele vai embora.

Nos dois casos, o resultado é o mesmo: "não usado" na verdade quer dizer "não encontrado por este método".

O que fazer antes de apagar

1. Liste os prefixos dinâmicos primeiro. Busque por template strings e concatenações que montam classes:

grep -rnoE '[A-Za-z0-9_-]+[-_]\$\{' . --include='*.js' --include='*.html'
grep -rnoE "[A-Za-z0-9_-]+[-_]['\"] *\+" . --include='*.js' --include='*.html'

O -o imprime só o prefixo, então a saída já vira uma lista. Toda classe do CSS que começa com um desses prefixos fica fora da lista de remoção até você provar o contrário. Atenção: nomes montados em duas etapas, como `${base}-${state}` ou ["status", key].join("-"), nenhum grep encontra. Esses você precisa achar lendo o código.

Se você usa PurgeCSS, transforme cada prefixo encontrado numa regra de safelist. O PurgeCSS extrai tokens do código-fonte; de `per-route-status-${key}` ele só vê per-route-status-, e a classe completa seria removida:

// purgecss.config.js
module.exports = {
  content: ["**/*.html", "**/*.js"],
  css: ["styles.css"],
  safelist: {
    standard: [/^per-route-status-/],
  },
};

O Tailwind usa a mesma ideia com safelist e pattern.

2. Prefira uma lista explícita a montar o nome. Um mapa deixa o nome inteiro visível para a busca:

const STATUS_CLASS = {
  dns: "per-route-status-dns",
  webrtc: "per-route-status-webrtc",
};
el.className = STATUS_CLASS[key];

Fica mais verboso, mas agora a busca pelo nome encontra o uso. Para 2.506 slugs isso não é prático em todos os casos, então use onde a lista é curta e estável.

3. Apague em lote pequeno e confira na tela. Remova um grupo, faça o deploy num ambiente de preview e abra as rotas e estados que usam aquele prefixo. Se uma tela mudou, o CSS estava vivo.

A regra

Zero resultados na busca só mostram que o nome não está escrito por extenso. Antes de apagar CSS, descubra como os nomes de classe são montados no seu projeto.

O MyIPScan é gratuito e os testes estão em myipscan.net.

Carregando publicação patrocinada...
1

Pois é, fiz isso uma vez, achando que tava reduzindo e otimizando um site, mas deu uma baita dor de cabeça, pra nunca mais. Depois adotei uma prática de marcar o que poderia se tornar obsoleto com tag DELME, e então limpava na entrega. Mas aquilo que sobra depois de algumas manutenções acaba ficando.