Lado do cliente vs. Lado do servidor vs. Pré-renderização para Web Apps

Publicados: 2022-03-11

Há algo acontecendo dentro da comunidade front-end recentemente. A renderização do lado do servidor está ganhando cada vez mais tração graças ao React e seu recurso de hidratação do lado do servidor integrado. Mas não é a única solução para entregar uma experiência rápida ao usuário com uma pontuação de tempo até o primeiro byte (TTFB) super rápida: a pré-renderização também é uma estratégia muito boa. Qual é a diferença entre essas soluções e um aplicativo totalmente renderizado pelo cliente?

Aplicativo renderizado pelo cliente

Como existem frameworks como Angular, Ember.js e Backbone, os desenvolvedores front-end tendem a renderizar tudo do lado do cliente. Graças ao Google e sua capacidade de “ler” JavaScript, ele funciona muito bem e é até amigável para SEO.

Com uma solução de renderização do lado do cliente, você redireciona a solicitação para um único arquivo HTML e o servidor a entrega sem nenhum conteúdo (ou com uma tela de carregamento) até que você busque todo o JavaScript e deixe o navegador compilar tudo antes de renderizar o conteúdo.

Sob uma conexão de internet boa e confiável, é bastante rápido e funciona bem. Mas pode ser muito melhor, e não precisa ser difícil fazê-lo assim. É o que veremos nas seções a seguir.

Renderização do lado do servidor (SSR)

Uma solução SSR é algo que costumávamos fazer muito, muitos anos atrás, mas tendemos a esquecer em favor de uma solução de renderização do lado do cliente.

Com as antigas soluções de renderização do lado do servidor, você criava uma página da Web – com PHP, por exemplo – o servidor compilava tudo, incluía os dados e entregava uma página HTML totalmente preenchida ao cliente. Foi rápido e eficaz.

Mas… toda vez que você navegava para outra rota, o servidor tinha que fazer todo o trabalho novamente: obter o arquivo PHP, compilá-lo e entregar o HTML, com todo o CSS e JS atrasando o carregamento da página para algumas centenas de ms ou mesmo segundos inteiros.

E se você pudesse fazer o primeiro carregamento de página com a solução SSR e, em seguida, usar um framework para fazer roteamento dinâmico com AJAX, buscando apenas os dados necessários?

É por isso que o SSR está ganhando cada vez mais força na comunidade porque o React popularizou esse problema com uma solução fácil de usar: O método RenderToString .

Esse novo tipo de aplicativo da web é chamado de aplicativo universal ou aplicativo isomórfico . Ainda há alguma controvérsia sobre os significados exatos desses termos e a relação entre eles, mas muitas pessoas os usam de forma intercambiável.

De qualquer forma, a vantagem desta solução é poder desenvolver um app server-side e client-side com o mesmo código e entregar uma experiência realmente rápida ao usuário com dados customizados. A desvantagem é que você precisa executar um servidor.

O SSR é usado para buscar dados e pré-preencher uma página com conteúdo personalizado, aproveitando a conexão de internet confiável do servidor. Ou seja, a conexão de internet do próprio servidor é melhor do que a de um usuário com lie-fi), então é capaz de pré-buscar e amalgamar dados antes de entregá-los ao usuário.

Com os dados pré-preenchidos, o uso de um aplicativo SSR também pode corrigir um problema que os aplicativos renderizados pelo cliente têm com o compartilhamento social e o sistema OpenGraph. Por exemplo, se você tiver apenas um arquivo index.html para entregar ao cliente, ele terá apenas um tipo de metadados, provavelmente os metadados de sua página inicial. Isso não será contextualizado quando você quiser compartilhar uma rota diferente, portanto, nenhuma de suas rotas será mostrada em outros sites com seu conteúdo de usuário adequado (descrição e imagem de visualização) que os usuários gostariam de compartilhar com o mundo.

Pré-renderização

O servidor obrigatório para um aplicativo universal pode ser um impedimento para alguns e pode ser um exagero para um aplicativo pequeno. É por isso que a pré-renderização pode ser uma alternativa muito boa.

Descobri esta solução com o Preact e sua própria CLI que permite compilar todas as rotas pré-selecionadas para que você possa armazenar um arquivo HTML totalmente preenchido em um servidor estático . Isso permite que você entregue uma experiência super rápida ao usuário, graças à função de hidratação Preact/React, sem a necessidade de Node.js.

O problema é que, como isso não é SSR, você não tem dados específicos do usuário para mostrar neste momento - é apenas um arquivo estático (e um tanto genérico) enviado diretamente na primeira solicitação, como está. Portanto, se você tiver dados específicos do usuário, aqui é onde você pode integrar um esqueleto lindamente projetado para mostrar ao usuário que seus dados estão chegando, para evitar alguma frustração da parte dele:

Usando um esqueleto de documento como parte de um indicador de carregamento

Há outro problema: para que essa técnica funcione, você ainda precisa ter um proxy ou algo para redirecionar o usuário para o arquivo correto.

Por quê?

Com um aplicativo de página única, você precisa redirecionar todas as solicitações para o arquivo raiz e, em seguida, a estrutura redireciona o usuário com seu sistema de roteamento integrado. Portanto, o carregamento da primeira página é sempre o mesmo arquivo raiz.

Para que uma solução de pré-renderização funcione, você precisa informar ao seu proxy que algumas rotas precisam de arquivos específicos e nem sempre do arquivo raiz index.html .

Por exemplo, digamos que você tenha quatro rotas ( / , /about , /jobs e blog ) e todas elas tenham layouts diferentes. Você precisa de quatro arquivos HTML diferentes para entregar o esqueleto ao usuário que permitirá que React/Preact/etc. reidratá-lo com dados. Portanto, se você redirecionar todas essas rotas para o arquivo raiz index.html , a página terá uma sensação desagradável e com falhas durante o carregamento, em que o usuário verá o esqueleto da página errada até que ela termine de carregar e substitua o layout. Por exemplo, o usuário pode ver um esqueleto de página inicial com apenas uma coluna, quando pediu uma página diferente com uma galeria semelhante ao Pinterest.

A solução é informar ao seu proxy que cada uma dessas quatro rotas precisa de um arquivo específico:

  • https://my-website.com → Redirecionar para o arquivo raiz index.html
  • https://my-website.com/about → Redirecionar para o arquivo /about/index.html
  • https://my-website.com/jobs → Redirecionar para o arquivo /jobs/index.html
  • https://my-website.com/blog → Redirecionar para o arquivo /blog/index.html

É por isso que esta solução pode ser útil para pequenos aplicativos - você pode ver como seria doloroso se você tivesse algumas centenas de páginas.

Estritamente falando, não é obrigatório fazê-lo dessa maneira - você pode simplesmente usar um arquivo estático diretamente. Por exemplo, https://my-website.com/about/ funcionará sem nenhum redirecionamento porque ele procurará automaticamente por um index.html dentro de seu diretório. Mas você precisa desse proxy se tiver urls de parâmetro— https://my-website.com/profile/guillaume precisará redirecionar a solicitação para /profile/index.html com seu próprio layout, porque profile/guillaume/index.html não existe e acionará um erro 404.

Um fluxograma mostrando como um proxy faz a diferença em uma solução de pré-renderização, conforme descrito no parágrafo anterior


Resumindo, existem três visualizações básicas em jogo com as estratégias de renderização descritas acima: Uma tela de carregamento, um esqueleto e a página inteira quando finalmente renderizada.

Comparando uma tela de carregamento, um esqueleto e uma página totalmente renderizada

Dependendo da estratégia, às vezes usamos todas essas três visualizações e às vezes pulamos direto para uma página totalmente renderizada. Apenas em um caso de uso somos forçados a usar uma abordagem diferente:

Método Desembarque (por exemplo / ) Estático (por exemplo, /about ) Dinâmico fixo (por exemplo /news ) Dinâmico parametrizado (por exemplo /users/:user-id )
Renderizado pelo cliente Carregando → Completo Carregando → Completo Carregando → Esqueleto → Completo Carregando → Esqueleto → Completo
Pré-renderizado Cheio Cheio Esqueleto → Completo HTTP 404 (página não encontrada)
Pré-renderizado com proxy Cheio Cheio Esqueleto → Completo Esqueleto → Completo
SSR Cheio Cheio Cheio Cheio

A renderização somente do cliente geralmente não é suficiente

Aplicativos renderizados pelo cliente são algo que devemos evitar agora porque podemos fazer melhor para o usuário. E fazer melhor, neste caso, é tão fácil quanto a solução de pré-renderização. É definitivamente uma melhoria em relação à renderização somente do cliente e mais fácil de implementar do que um aplicativo totalmente renderizado no lado do servidor.

Um aplicativo SSR/universal pode ser realmente poderoso se você tiver um aplicativo grande com muitas páginas diferentes. Ele permite que seu conteúdo seja focado e relevante ao conversar com um rastreador social. Isso também é verdade para robôs de mecanismos de pesquisa, que agora levam em consideração o desempenho do seu site ao classificá-lo.

Fique atento para um tutorial de acompanhamento, onde vou percorrer a transformação de um SPA em versões pré-renderizadas e SSR e comparar seu desempenho.

Relacionado: Visão geral de geradores de sites estáticos populares