Pré-renderizar rotas com o React-snap

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

react-snap é uma biblioteca de terceiros que pré-renderiza páginas do seu site em arquivos HTML estáticos. Isso pode melhorar o tempo de First Paint no seu app.

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

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

Por que isso é útil?

O principal problema de desempenho com aplicativos de página única grandes é que o usuário precisa esperar que os pacotes de JavaScript que compõem o site terminem de ser transferidos antes de poder acessar o conteúdo real. Quanto maiores os pacotes, maior será o tempo de espera do usuário.

Para resolver isso, muitos desenvolvedores usam a abordagem de renderizar o aplicativo no servidor em vez de apenas inicializá-lo no navegador. Com cada transição de página/rota, o HTML completo é gerado no servidor e enviado para o navegador, o que reduz os tempos de primeira pintura, mas tem o custo de um tempo mais lento para o primeiro byte.

A pré-renderização é uma técnica separada que é menos complexa do que a renderização do servidor, mas também oferece uma maneira de melhorar os tempos de First Paint no aplicativo. Um navegador sem cabeça, ou sem 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.

react-snap

O react-snap usa o Puppeteer para criar arquivos HTML pré-renderizados de rotas diferentes 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 ao 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). Nesse caso, ReactDOM.hydrate é usado para anexar listeners de evento ao HTML já criado em vez de criar um novo.

A criação do aplicativo agora vai gerar arquivos HTML estáticos como payloads para cada rota rastreada. Para conferir o payload do 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 foto depois mostra o conteúdo renderizado.

Flash de conteúdo sem estilo

Embora o HTML estático agora seja renderizado quase imediatamente, ele ainda não tem estilo por padrão, o que pode causar o problema de mostrar um "flash de conteúdo sem estilo" (FOUC). Isso pode ser especialmente perceptível se você estiver usando uma biblioteca CSS-in-JS para gerar seletores, já que o pacote JavaScript terá que terminar a execução antes que os estilos possam ser aplicados.

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

"reactSnap": {
  "inlineCss": true
}

A visualização de resposta no Chrome DevTools agora mostra a página estilizada com o CSS crítico inline.

Uma comparação de antes e depois. A imagem depois mostra que o conteúdo foi renderizado e estilizado devido ao CSS crítico inline.

Conclusão

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

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