Image for post
Image for post
Vários produtos e plataformas, e como manter o CSS em tudo isso?

Melhorando a qualidade do CSS no Facebook

Com milhares de engenheiros trabalhando em uma variedade de produtos dentro do Facebook, enfrentamos alguns desafios únicos quando se trata de qualidade de código.

Não lidamos apenas com uma enorme base de código, como também, elas crescem e mudam rapidamente — novos recursos sendo adicionados, os já existentes sendo melhorados e coisas sendo reorganizadas.

E falando de CSS, isso significa ter milhares de arquivos que estão em contínua mudança.

Nós já tentamos garantir uma qualidade do código CSS em vários níveis — revisão de código, guias de estilo e refatoração — erros não-intencionais também podem ser eliminados com análise estática antes de serem comitados.

Até rencentemente, usávamos um CSS linter criado por nós para pegar os erros básicos e garantir a consistência do estilo de código. Essa essa solução foi suficiente no decorrer dos anos, mas queríamos algo mais robusto.

Expressão regular não é suficiente

O linter antigo era, básicamente, algumas expressões regulares analisando e substituindo regras no código. Analisar própriamente o código CSS não é um grande problema, mas, ficar em dia com os custom vendors e especificações, isso é bem desafiador.

Aqui um exemplo de uma antiga expressão regular:

Manter um punhado de regras doidas como essa não é nada legal. Era difícil de alterar e entender. E também tinha problemas de performance. Para cada regra, tínhamos que analisar todo o código novamente, imagine várias regras como essa!… not cool dude, not cool!

AST ou Árvore de Sintaxe Abstrata

Nós decidimos que a nova solução seria um analisador de código CSS baseado na real especificação. Sabendo que o código tem que ser semânticamente válido para esse tipo de ferramenta funcionar, nós não podeíamos tratar toda a nossa base de código CSS como um gigante arquivo de texto. Essa nova abordagem, significaria uma enorme melhora na análise de código CSS, conseguindo identificar problemas que passariam despercebido e resultando em silenciosos erros de renderização.

Que tipo de problemas?

Aqui um pedaço dos escuros e desconhecidos pedaços da nossa grande base de código:

Consegue identificar os problemas? Escrita errada no nome da propriedade, valor hexadecimal incorreto, separadores errados — os navegadores simplesmente ignoram todos esses, o que é de fato, bem longe do que o desenvolvedor quer.

Não demorei muito para ver que o PostCSS seria uma ótima ferramenta para esse trabalho — um analisador baseado nos padrões do CSS com ótima arquitetura modular. Nós então escolhemos o Stylelint como nosso CSS linter. Se utiliza do PostCSS, é flexível e bem suportado!

Parecido com linters e parsers para JavaScript, como o Esprima e ESLint, PostCSS e Stylelint te dá acesso a AST (Árvore de Síntaxe Abstrata). AST torna mais fácil o acesso aos nós em qualquer condição: Estamos usando o nome de classe correto? Estamos incluindo abstrações corretas? Estamos removendo ou não suportando algumas extensões? Existe problemas de internacionalização?

No exemplo a seguir, estamos iterando através de todas as declarações e procurando por “text-transform: uppercase”:

Nós também podemos analisar e desconstruir funções de baixo nível linear-gradient. No próximo exemplo, um pouco mais complexo, estamos encontrando todas as declrações de linear-gradient e verificando seu primeiro argumento:

O código é relativamente fácil de entender e atualizar. E toda essa verificação irá funcionar, não importa o formato do CSS, também não importa aonde essas regras foram declaradas (no início do arquivo, dentro de blocos como media queries ou keyframes).

Sabe aqueles problemas que citei? É uma ótima sensação ver o PostCSS e o Stylelint vasculhando nossos arquivos, procurando por erros de escrita, separadores, valores dentro de funções, ou até mesmo ! important (que, na verdade, deveria ser !important), seletores complexos, propriedades não-padrão e vários outros!

Regras customizadas

Nós usamos algumas regras já existentes do Stylelint, tais como, declaration-no-important, selector-no-universal, e selector-class-pattern.

E, nossas regras customizadas são disponibizadas através de alguns plugins que criamos, Stylelint tem um ótimo mecanismo para isso! Algumas das regras que temos incluem:

  • slow-css-properties: para avisar sobre propriedades sensíveis há performance como opacity ou box-shadow (quase que, para saber que eles estão lá)
  • filters-with-svg-files: para avisar sobre filtros que não são suportados pelo navegador Edge, quando referênciamos arquivos SVG
  • use-variables: para avisar sobre valores que poderiam ser substituídos por variáveis já existentes (nós usamos uma abstração chamada **var(…)**)
  • common-properties-whitelist: para achar potenciais propriedades não existentes (mais para erro de escrita)
  • mobile-flexbox: para avisar sobre declarações Flex que não são suportadas em navegadores mobile antigos
  • text-transform-uppercase: para avisar sobre “text-transform: uppercase” (que não é internacionalmente amigável)

Nós também contribuímos algumas regras e melhorias ao Stylelint e estamos planejando criar um ciclo de contribuições, sejam elas diretamente ao Styelint ou em um repositório próprio.

Substituição automática

Um aspecto importante do nosso processo de lint, é a auto-formatação. Com o Linter, é possível identificar se algo não passou nas nossas regras e perguntar se o desenvolvedor gostaria de substituir a declaração para algo de acordo com a regra. Isso é muito poderoso e nos salva um grande tempo. A última coisa que você quer fazer durante um commit é verificar se existe erros de lint, voltar e arrumar todos, em vários arquivos, especialmente aqueles erros de ordem alfabética (not cool dude, not cool!). É bem mais conveniente deixar uma ferramente de auto correção fazer o trabalho e te salvar tempo!

Infelizmente, Styelint não tem, por padrão, uma ferramente de auto formatação (e, sem dúvida, não deveria ser de responsabilidade do linter fazer isso), então, nós tivemos que reimplementar algumas das regras existentes do Stylelint e adicionar o suporte para auto correção através da nossa infra-estrutura. Enquanto isso, estamos discutindo potenciais mudanças no Styelint para torna-lo mais simples nessas tarefas no futuro.

Image for post
Image for post

Testando tudo, e todos!

Um dos grandes problemas do nosso linter anterior era que não tínhamos testes unitários. Isso era preocupante, porquê, afinal, estamos lidando com algo que analisa nosso código de um modo arbitrário. Quando estávamos reescrevendo nosso linter para usar o Stylelint, nós adicionamos testes para cada regra, garantindo que cara uma delas iria analisar o problema certo, ignorando coisas irrelevantes e sugerindo as substituições corretas.

Nós usamos o confiável Jest framework (e trabalhamos com a equipe do Stylelint para adicionar suporte para ele) e agora nós temos uma maneira de fácil entendimento e escrita, como:

O que o futuro nos aguarda

Essa reescrita foi apenas um primeiro passo para um qualidade superior em nosso CSS. Existem várias regras úteis que estamos planejando colocar (algumas customizadas e outras já padrões) — todas com foco em procurar erros comuns, advocar melhores práticas e controlar o estilo de código. Nós já fazemos isso com JavaScript (usando ESLint) então, não há razão para não fazer isso com CSS.

O linter já está integrado ao Phabricator, nossa ferramenta de colaboração. Com avisos e dicas sendo mostradas em cada revisão.

Image for post
Image for post

Isso torna o processo de linting uma etapa importante no processo de commit e colaboração.

Outra grande vantagem em ter um analisador de CSS decente é a possibilidade de extrair estatísticas precisas sobre o nosso código. Quais são as propriedades/valores menos usadas? Talvez elas devem ser removidas ou substituídas (criando um arquivo menor). Quais sãos os valores mais utilizados para color/font-size e z-index? Talvez eles devam ser separados em componentes reutilizáveis ou variáveis. Quais são os seletores mais complexos? Talvez tenha um problema de performance.

Tudo isso pode ajudar na manutenção e qualidade a longo prazo.

React e estilos inline

Vale mencionar, que CSS em JavaScript é um conceito que está ganhando força ultimamente com a comunidade do React. E hoje em dia, linters CSS são praticamente irrelevantes em casos onde o CSS é definido em maneiras não tradicionais. O linter tem foco em analisar arquivos CSS tradicionais, mas pode futuramente, se adaptar para analisar declarações definidas como objetos JS. PostCSS tem uma API nativa para JS, o que torna bastante simples a idéia.

Ainda estamos explorando CSS em JavaScript no Facebook, ainda estamos nos primeiros experimentos, e nós ainda temos uma grande quantidade de código CSS para manter. Por isso, o linter funciona do modo que precisamos.

Unidos crescemos

Nós estamos animados de usar uma ferramenta de código aberto e contribuir de volta, nos esforçamos para isso. Esperamos que isso possa contruir para uma plataforma mais moderna de regras e estilos para que todos possam contribuir.

Obrigado a todos da equipe de JS Infra e Webspeed, e todos os outros que ajudaram nessa reescrita; David Clark e Richar Hallows do Stylelint, que foram extremamente comprometidos com as idéias; assim como toda a comunidade que tornou possível uma ferramenta fantástica como o PostCSS.

Essa é a essência do trabalho colaborativo.

Créditos

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store