RM
Voltar
Published on

Porquê Server Components não suportam CSS-in-JS?

Entenda como funciona uma biblioteca CSS-in-JS e porquê a maioria são incompatíveis com Server Components.


Time to read
6min de leitura

Bibliotecas como Styled-Components e Emotion não lidam bem com server components, e isso se trata da necessidade de Javascript em tempo de execução para gerar os estilos.

Server Components e Server-side Rendering

Antes de tudo é preciso esclarecer a diferença entre Server Components e Server-side Rendering (SSR).

SSR ao que todos conhecem é renderizar uma página HTML no lado do servidor. Basicamente é o conceito de gerar todo o arquivo HTML de uma página, que contém a UI inicial, no lado do servidor, e depois enviar ao cliente. Segue basicamente este fluxo:

  1. Usuário acessa a página.
  2. O Node.js da aplicação recebe a requisição, que produz e retorna o HTML completo da página contendo a UI inicial da página.
  3. Quando esse HTML chega ao browser do usuário, o React renderiza novamente os mesmos componentes, repetindo o trabalho feito no servidor. Esse processo é conhecido como hidratação, em vez de gerar novos elementos HTML, ele adota os elementos HTML já gerados. Além disso, é necessário adicionar interatividade ao HTML estático retornado pelo servidor, adicionando eventos, etc.

Os principais benefícios do SSR são:

Mas esse modelo possui uma limitação. Todo código escrito será executado tanto no servidor quanto no cliente. Não existe maneiras de criar componentes que irão renderizar apenas no lado do servidor.

Vamos supor o seguinte código:

export default function Home() {
  const posts = db.query('/posts');
  
  return (
    <main>
      {posts.map(item => (
        <Post key={item.id} {...item} />
      ))}
    </main>
  );
}

O código acima funcionaria muito bem rodando apenas no servidor, mas ao rodar novamente no client produziria um erro, já que o cliente não possui acesso ao banco de dados. Ou seja, não é possível dizer ao React "Rode esse código apenas no servidor".

Alguns dos frameworks mais famosos como o Next.js vieram com as suas próprias soluções, onde adicionam camadas de código que rodam fora do React, para então rodar apenas no servidor. No Next.js temos o getServerSideProps, que busca os dados necessários e então retorna ao cliente em formato de props React. O problema é que tais funções precisam ficar no início do fluxo, no topo da "página", não é possível adicionar um getServerSideProps em qualquer lugar.

Os React Server Components vieram para solucionar esse problema. Com eles é possível fazer recursos de "servidor" em componentes React. A partir da versão 18 do React, todos os componentes são server components por padrão, e para dizer que um componente deve rodar tanto no servidor quanto no cliente, é necessário adicionar a flag "use client".

Então porquê as bibliotecas CSS-in-JS não funcionam em server components?

Bom, existem vários motivos aos quais as bibliotecas mencionadas não funcionam bem com server components. Mas o motivo principal é que elas foram criadas para rodar no browser.

Como funciona uma biblioteca CSS-in-JS?

Vamos olhar para este trecho de código que utiliza styled-components:

const Button = styled.button`
  background: blue	
	font-size: 2rem;
	color: white;
`;

export default function Dashboard() {
	return (
		<Button>Click me!</Button>
	);
}

Como o componente Button produz um botão estilizado com as regras CSS que passamos? O processo é basicamente esse:

Este fluxo básico funciona tanto em SSR quanto CSR (Client-side Rendering). No entanto, a medida que o usuário interage com a aplicação, é necessário criar novos estilos, remover, ou modificar estilos já existentes.

Vamos pensar no seguinte caso:

const Loader = styled.div`
	color: grey;
	font-style: italic;
`

function Form() {
	const { formState: { isSubmitting  } = useForm();
	
	return (
		<Form>
			{isSubmitting ? (
				<Loader>
			) : (
				...Rest of code
			)}
		</Form>
	)
 }

No trecho de código acima, os estilos para o componente estilizado Loader não são incluídos no CSS inicial da página, e depois, quando o formulário estiver sendo submetido, esses estilos devem ser incluídos na <style> tag do nosso HTML. E aí que está o grande ponto.

Internamente, o Styled Components faz grande uso da Context Api, do React. Ele utiliza para gerenciar os estilos da aplicação, em um valor global que pode ser compartilhado entre qualquer componente da aplicação. Dessa forma, qualquer componente pode atualizar os estilos renderizados da página, a medida que são incluídos/removidos da árvore DOM.

Além disso, também sabemos que o Styled Components fornece suporte para "Theming" através de um <ThemeProvider> que fica por volta da aplicação, fornecendo um estado global que pode ser acessado por todo e qualquer componente da aplicação, que permite que os estilos dos componentes sejam dinamicamente ajustados com base no tema fornecido pelo contexto. Esse é outro recurso muito utilizado pela biblioteca que faz uso da Context Api.

Infelizmente, como todos sabem, RSC não suportam a Context Api, e é neste ponto que existe a incompatibilidade.

A maioria das bibliotecas CSS-in-JS precisam de uma maneira de compartilhar estilos entre os componentes, e a Context Api é a forma mais eficiente de fazer isso. No entanto, não existe nenhuma forma nativa no React para repetir esse comportamento em Server Components.

Conclusão

Depois de mais de 1 ano e meio do lançamento de React Server Components, ainda não existem bibliotecas CSS-in-JS que suportem Server Components e forneçam todos os recursos que antes tinhamos acesso nas principais bibliotecas CSS-in-JS. Entretanto, esse é um tópico ainda em constante evolução.

Existe um repositório que propõe uma ferramenta CSS-in-JS dos "sonhos", que discorre através de algumas alternativas para resolver o problema da dependência da Context Api. Por mais que o autor do repositório não tenha chego em resultados 100% utilizáveis e concretos, a discussão é bem interessante e mostra evoluções acerca deste problema, utilizando-se de outras APIs do React para tal.

O repositório também discute outras ferramentas como o Linaria e o PandaCSS que são ferramentas CSS-in-JS que não exigem Javascript em runtime e são compatíveis com RSC. Vale a pena conferir.