Por que usar Server Components? - Uma breve história da web
Esse post é uma tradução do artigo Why Server Components - A Brief History of Web.
Esse post terá apenas a metade inicial do artigo, pois o Tabnews tem um limite de 20000 palavras por post. O restante do artigo estará em um dos comentários logo abaixo.
De acordo com o Stack Overflow survey 2023, Next.js é o terceiro framework web mais desejado atualmente, além de ser o sexto mais admirado entre os desenvolvedores. Apesar de seu antigo Pages Router ser ótimo, eles introduziram um novo App Router na versão 13 do framework. Com essa mudança, eles também migraram para o uso de Server Components que podem ser vistos como um próximo nível de renderização no servidor.
Para entender por que Next.js e Server Components são muito mais do que apenas aplicações React tradicionais do lado do cliente, este artigo guiará você desde o início da web, através de diferentes tipos de renderização no servidor com todos os seus benefícios, até o mais novo estado do desenvolvimento web com Next.js Server Components.
Neste Artigo
- De Server Rendering para SPAs e então de volta para o Servidor
- Client Components vs Server Components
- Server Side Rendering (SSR) vs Static Site Generation (SSG)
- Revisitando Client Components vs Server Components
- Qual solução de renderização eu devo usar?
De Server Rendering para SPAs e então de volta para o servidor
Para entender melhor os Server Components, nós precisamos falar sobre por que eles foram introduzidos. Para isso, nós vamos precisar de uma pequena aula de história.
Nos dias do desenvolvimento web antigo e tradicional, um site consistia de um servidor renderizando código HTML, enviando-o pela internet para um browser que mostrava o HTML já renderizado ao usuário. Com isso, você tinha CSS e alguns pequenos arquivos de JavaScript para gerenciar as interações do usuário e a navegação para outras páginas no site (e também para mostrar um contador de visitas legal, que era meio que obrigatório).
Tecnologias mais novas surgiram e nós ganhamos smartphones e computadores melhores com muito mais performance. A internet evoluiu e single pages applications (SPAs) passaram a ser o novo padrão, o que basicamente significava que apenas uma página inicial era enviada para o client. Ao navegar ou interagit com a página, requisições REST eram usaads para recuperar dados do servidor e modificar a página sem efetivamente navegar para outra página do site.
Um dos maiores pivôs para essa evolução foi a biblioteca jQuery e seu principio continuou crescendo com frameworks modernos, como React, Angular e Vue que em primeiro lugar renderizavam tudo no lado do cliente, com suporte para usar server side rendering (SSR) opcionalmente. À medida que a web migrou para SPAs nós começamos a chamar sites com funcionalidades avançadas de aplicativos web (web applications).
Mais e mais fremeworks de aplicativos web surgiram e diferentes formas de pré-renderizar esses aplicativos surgiram. Pré-renderizar páginas web em requisições com SSR não era o suficiente, frameworks podiam também adicionar suporte para pré-renderizar páginas em tempo de compilação, assim chamado static site generation (SSG).
Em breve veremos mais de perto SSR e SSG e no fim desse artigo nós vamos discutir prós e contras de renderização no servidor. Mas por hora, vamos esquecer o por que e focar no o quê e como.
Onde nós estamos hoje, não é uma questão sobre renderização no lado do cliente ou servidor, nós chegamos em um ponto onde podemos escolher renderizar pequenas partes do site diferendemente e é aí que Client e Server Components entram.
Client Components vs Server Components
Se você já usou frameworks de SPA como React e Angular, você já deve estar familiarizado com Client Components. Eles são basicamente como um componente React é em sua natureza, um pouco de códico JavaScript que renderiza um componente em uma página logo que chega no navegador.
Por outro lado, Server Components são renderizados em HTML no servidor. Quando eu falo isso, não me refiro a pré-renderizar HTML para uma página completa com SSR ou SSG, eu literalmente quero dizer renderizar um pequeno componente, como um pequeno componente React. Essa é a granularidade oferecida pelo novo App Router do Next.js.
Para ter uma melhor visão disso, vamos olhar para as soluções antigas de pré-renderização e então voltar para os Server Components.
Server Side Rendering (SSR) vs Static Site Generation (SSG)
O básico sobre SSR e SSG são o mesmo: pré-renderizar código HTML no servidor e então buscar (fetching) JavaScript para fazer a página ser interativa, em um processo chamado hydration. Dependendo do framework, a navegação pode resultar na busca de páginas completamente novas do servidor ou ser manipulada por hydration, como faria uma SPA.
Quando usamos SSR como uma solução de pré-renderização, uma página completa é renderizada em HTML no servidor quando uma página é requisitada. O servidor então vai também buscar o JavaScript e iniciar o processo de hydration.
Em vez disso, SSG permite você a pré-renderizar a aplicação já em tempo de compilação, que faz possível enviar a mesma página HTML rapidamente para qualquer usuário sem precisar renderizar uma página em tempo de execução.
Enquanto SSG permite enviar páginas web instantâneamente, ele não permite enviar HTML diferentes para usuários diferentes. Todos os usuários vão receber o mesmo conteúdo. Renderizando dinamicamente baseado nos dados do usuário não é possível com isso.
SSG não permite que você altere o HTML ao longo do tempo, já que todo o código é gerado no tempo de compilação. Para resolver esse problema, Next.js oferece suporte a uma coisa chamada incremental static regeneration (ISR). O que isso faz é permitir que você, manualmente, sob demanda ou periódicamente, regerar uma página estática gerada.
Apesar de ISR existir no antigo Pages Router, ele não está disponível com o novo App Router, pois o seu bastão foi passado para os Server Components.
Revisitando Client Components vs Server Components
Então, agora que sabemos sobre as antigas opções para renderizar páginas no servidor, nós podemos voltar e ver o que Clent e Server Components realmente são. Veja essa imagem, ela mostra uma página web com Client e Server Components de forma alternada.
Como mensionado anteriormente no artigo, Server Components permitem a você renderizar componentes individuais puramente no servidor, enquando outros componentes na mesma página permanecem como Clients Componentes no lado do cliente (com Next.js eles são pré-renderizados uma vez no servidor e hidratados no cliente). A imagem acima mostra e exemplifica como isso pode ser. Os componentes em verde são renderizados em HTML no servidor, ao passo que os em azul são renderizados com JavaScript no cliente.
Isso significa que o Next.js permite decidir para cada componente se deve ser pré-renderizado no servidor ou se precisa ser renderizado no lado do cliente. Como vamos ver depois, na seção Renderização Estática vs Dinâmica, o Next.js também irá determinar automáticamente se esses Server Components precisam ser renderisados e tempo de execução ou se precisam ser renderizados antecipadamente em tempo de compilação.
Qual solução de renderização devo usar?
Como vimos, existem muitas opções disponíveis para renderizar aplicações web modernas e, se você usar o Next.js 13, poderá escolher entre todas as opções discutidas anteriormente. Se você iniciar um novo projeto, recomendo usar o novo App Router. Ele está pronto para produção, apesar de outras funcionalidades relacionadas ainda estarem em alfa ou beta.
Para fazer a sua vida mais fácil, nós vamos ver quais soluções de renderização escolher para o Pages Router e para o novo App Router.
Next.js Pages Router
Com o Pages Router, você tem quatro opções de renderização para escolher:
- Client Side Rendering (CSR)
- Server Side Rendering (SSR)
- Static Site Generation (SSG)
- Incremental Static Regeneration (ISR)
Lembrando que todas essas opções são por página. O comportamento normal é que aplicações usem mais de uma dessas opções. Por exemplo, páginas de informações tal como uma página de "sobre nós" pode geralmente usariam SSG, enquanto outras páginas com dados mais dinâmicos usariam SSR.
Como nós veremos mais tarde no artigo, o desenvolvimento web moderno tende a favorecer renderização no servidor ao invés de no lado do cliente. Por isso CSR só é recomendado se realmente há necessidade disso. Algums casos onde é necessário ou recomendado renderizar a aplicação no lado do cliente são:
- Quando você precisa usar APIs específicas do browser
- Quando você precisa da localização em tempo real via API de geolocalização da Web ou IP
- Quando seus dados dependem de dados armazenados no navegador
- Quando apps estão se comunicando em uma rede ponto a ponto
- Quando os dados mudam frequentemente podemos querer manter o carregamendo do lado do cliente para não sobrecarregar o servidor
Na maioria dos outros casos, usar alguma forma de pré-renderização no servidor é recomendado. O objetivo é armazenar em cache o conteúdo gerado o máximo possível. Se o site é completamente estático, SSG é geralmente preferido, se possível.
Se você tem muitas páginas para renderizar em tempo de compilação, ou se as páginas estáticas precisam ser atualizadas ocasionalmente, ISR deve ser um recurso exelente. Com ISR, as construções podem ser geradas em tempo de execução quando você precisa delas e então regeradas manualmente ou definindo um tempo de validação de cache.
Se uma página não é completamente estática e dos dados não mudam com o tempo, mas também dependem de informação autenticada do usuário ou dos cabeçalhos da requisição, SSR ou CSR é provavelmente o que você vai precisar usar em vez disso.
Next.js App Router
Com o App Router nós não temos tantas alternativas. As duas opções principais são Client ou Server Components.
O conceito de renderização estática e dinâmica ainda é relevante quando nós usamos o App Router, mas não é notável. Os detalhes sore isso são um pouco complicados, mas nós vamos discutir na seção Renderização Estática vs Dinâmica.
A parte fácil de entender é quando usamos Server Components. Assim como no Pages Router, SSR é preferido quando usamos o App Router. Isso significa que nós devemos usar Server Components enquanto não temos razões para usar Client Components. É também por isso que Server Components são o padrão no Next.js.
Isso pode soar estranho, mas nos casos em que usamos Client Components são um pouco diferentes de quando usamos CSR no Pages Router. A razão é porque toda a estrutura e design fundamentais é diferente com o App Router, então nós não podemos usar exatamente as mesmas regras.
Com o App Router, você pode seguir uma simples regra: se existe a necessidade de usar o navegador de qualquer forma ou armazenar qualquer estado que mudará o resultado das interações do usuário, então você deve usar um Client Component, caso contrário deve usar um Server Component.
Mais explícitamente, um Client Component vai ser necessário quando:
- Você precisa de APIs específicas do navegador
- Você precisa saber a localização real do usuário com alguma API de geolocalização via web ou IP
- seus dados dependem de dados armazenados no navegador
- o componente usa um hook de ciclo de vida ou de gerenciamento de estado como
useState
,useReducer
,useEffect
ouuseContext
- o componente usa um hook persinalizado que usa ciclo de vida ou gerenciamento de estado
- os componentes precisam ser interativos, isto é, quando usam listeners
onClick
ououChange
em elementos do DOM - se você ainda usa React Class Components por qualquer razão estranha
Isso pode parecer demais, mas lembre-se, uma grande parte das aplicações web é normalmente estática e nunca é alterada ou interage. Por exemplo, esse artigo inteiro é estático (no Tabnews não é tão estático assim XD), é apenas textos, imagens e links.
Server Components não são só gerados estáticamente em tempo de construção. Como nós vamos ver depois, você ainda pode buscar (fetch) dados de APIs neles, até com dados não armazenados em cache dinâmicamente. Você pode ler cookies e headers e eles permitem você ler dados sensíveis no servidor e evitar o envio de respostas enormes e dependências de JavaScript para o cliente.