Pré-renderizar rotas com o React-snap

Não renderiza no lado do servidor, mas ainda quer acelerar o desempenho do seu site do React? Experimente a pré-renderização.

A react-snap é uma biblioteca de terceiros que pré-renderiza as páginas do site em arquivos HTML estáticos. Isso pode melhorar os tempos de First Paint no seu aplicativo.

Confira uma comparação do mesmo aplicativo com e sem pré-renderização carregada em uma conexão 3G simulada e um dispositivo móvel:

Uma comparação de carregamento lado a lado. A versão que usa a pré-renderização é carregada 4,2 segundos mais rápido.

Por que isso é útil?

O principal problema de desempenho com grandes aplicativos de página única é que o usuário precisa aguardar até que os pacotes JavaScript que compõem o site terminem o download antes de poder ver qualquer conteúdo real. Quanto maiores os pacotes, mais tempo o usuário terá que esperar.

Para resolver isso, muitos desenvolvedores usam a abordagem de renderizar o aplicativo no servidor, em vez de apenas inicializá-lo no navegador. Em cada transição de página/rota, o HTML completo é gerado no servidor e enviado ao navegador, o que reduz os tempos da First Paint, mas custa um Tempo até o primeiro byte mais lento.

A pré-renderização é uma técnica separada que é menos complexa que a renderização do servidor, mas também oferece uma maneira de melhorar os tempos da First Paint no aplicativo. Um navegador headless ou sem uma interface do usuário é usado para gerar arquivos HTML estáticos de cada rota durante o tempo de build. Esses arquivos podem ser enviados com os pacotes JavaScript necessários para o aplicativo.

clique de reação

O react-snap usa o Puppeteer (em inglês) para criar arquivos HTML pré-renderizados de diferentes rotas no aplicativo. Para começar, instale-o como uma dependência de desenvolvimento:

npm install --save-dev react-snap

Em seguida, adicione um script postbuild em package.json:

"scripts": {
  //...
  "postbuild": "react-snap"
}

Isso executaria automaticamente o comando react-snap sempre que um novo build dos aplicativos fosse feito (npm build).

A última coisa que você precisa fazer é mudar a forma como o aplicativo é inicializado. Mude o arquivo src/index.js para o seguinte:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
const rootElement = document.getElementById("root");

if (rootElement.hasChildNodes()) {
  ReactDOM.hydrate(<App />, rootElement);
} else {
  ReactDOM.render(<App />, rootElement);
}

Em vez de usar apenas ReactDOM.render para renderizar o elemento raiz do React diretamente no DOM, ele verifica se algum nó filho já está presente para determinar se o conteúdo HTML foi pré-renderizado (ou renderizado no servidor). Se esse for o caso, ReactDOM.hydrate será usado para anexar listeners de eventos ao HTML já criado em vez de criá-lo novamente.

A criação do aplicativo agora gera arquivos HTML estáticos como payloads para cada rota rastreada. Para conferir a aparência do payload HTML, clique no URL da solicitação HTML e, em seguida, na guia Previews no Chrome DevTools.

Uma comparação de antes e depois. A sequência mostra que o conteúdo foi renderizado.

Flash de conteúdo sem estilo

Embora o HTML estático agora seja renderizado quase imediatamente, ele ainda permanece sem estilo por padrão, o que pode causar o problema de mostrar um "flash de conteúdo sem estilo" (FOUC, na sigla em inglês). Isso é ainda mais perceptível se você estiver usando uma biblioteca CSS em JavaScript para gerar seletores, já que o pacote JavaScript terá que terminar a execução antes que qualquer estilo possa ser aplicado.

Para evitar isso, o CSS crítico ou a quantidade mínima de CSS necessária para que a página inicial seja renderizada pode ser inline diretamente no <head> do documento HTML. react-snap usa outra biblioteca de terceiros em segundo plano, minimalcss, para extrair qualquer CSS essencial para rotas diferentes. Para ativar, especifique o seguinte no arquivo package.json:

"reactSnap": {
  "inlineCss": true
}

A visualização da resposta no Chrome DevTools agora vai mostrar a página estilizada com CSS essencial inline.

Uma comparação de antes e depois. A sequência mostra que o conteúdo foi renderizado e está estilizado devido ao CSS crítico embutido.

Conclusão

Se você não estiver renderizando rotas do lado do servidor no seu aplicativo, use react-snap para pré-renderizar o HTML estático para seus usuários.

  1. Instale-o como uma dependência de desenvolvimento e comece apenas com as configurações padrão.
  2. Use a opção experimental inlineCss para inserir CSS inline se ela funcionar no seu site.
  3. Se você estiver usando a divisão de código no nível de um componente em qualquer rota, tenha cuidado para não pré-renderizar um estado de carregamento para os usuários. O README react-snap (link em inglês) abrange esse assunto com mais detalhes.