Procesamiento previo de rutas con reacción-snap

¿No estás renderizando el servidor, pero quieres acelerar el rendimiento de tu sitio de React? Prueba la renderización previa.

react-snap es una biblioteca de terceros que renderiza previamente las páginas de tu sitio en archivos HTML estáticos. Esto puede mejorar los tiempos de First Paint en tu aplicación.

A continuación, se muestra una comparación de la misma aplicación con y sin renderización previa cargada en una conexión 3G simulada y un dispositivo móvil:

Una comparación de carga en paralelo. La versión que usa la renderización previa se carga 4.2 segundos más rápido.

¿Por qué es útil?

El principal problema de rendimiento de las aplicaciones grandes de una sola página es que el usuario debe esperar a que los paquetes de JavaScript que conforman el sitio terminen de descargarse para poder ver el contenido real. Cuanto más grandes sean los paquetes, más tiempo tendrá que esperar el usuario.

Para resolver esto, muchos desarrolladores adoptan el enfoque de renderizar la aplicación en el servidor en lugar de iniciarla solo en el navegador. Con cada transición de página o ruta, el HTML completo se genera en el servidor y se envía al navegador, lo que reduce los tiempos del primer byte, pero disminuye el tiempo hasta el primer byte.

La renderización previa es una técnica independiente que es menos compleja que la renderización del servidor, pero que también proporciona una forma de mejorar los tiempos de la primera pintura en tu aplicación. Se usa un navegador sin interfaz gráfica, o uno sin interfaz de usuario, para generar archivos HTML estáticos de cada ruta durante el tiempo de compilación. Luego, estos archivos se pueden enviar junto con los paquetes de JavaScript que se necesitan para la aplicación.

reaccionar

react-snap usa Puppeteer para crear archivos HTML renderizados previamente de diferentes rutas en tu aplicación. Para comenzar, instálalo como una dependencia de desarrollo:

npm install --save-dev react-snap

Luego, agrega una secuencia de comandos postbuild a tu package.json:

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

Esto ejecutaría automáticamente el comando react-snap cada vez que se creara una compilación nueva de las aplicaciones (npm build).

Lo último que deberás hacer es cambiar la forma en que se inicia la aplicación. Cambia el archivo src/index.js por lo siguiente:

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);
}

En lugar de solo usar ReactDOM.render para renderizar el elemento raíz de React directamente en el DOM, se verifica si ya hay nodos secundarios presentes para determinar si el contenido HTML se renderizó previamente (o se renderizó en el servidor). Si ese es el caso, en lugar de crearlo de nuevo, se usa ReactDOM.hydrate para adjuntar objetos de escucha de eventos al HTML ya creado.

Ahora, compilar la aplicación generará archivos HTML estáticos como cargas útiles para cada ruta que se rastree. Para verificar cómo se ve la carga útil HTML, haz clic en la URL de la solicitud HTML y, luego, en la pestaña Vistas previas de las Herramientas para desarrolladores de Chrome.

Una comparación del antes y el después. La toma posterior muestra que el contenido se renderizó.

Flash de contenido sin estilo

Si bien el HTML estático ahora se procesa casi de inmediato, sigue sin cambiar de diseño de forma predeterminada, lo que puede causar que se muestre un "destello de contenido sin diseño" (FOUC). Esto puede ser especialmente notorio si usas una biblioteca CSS-in-JS para generar selectores, ya que el paquete de JavaScript tendrá que terminar de ejecutarse antes de que se puedan aplicar los diseños.

Para evitar esto, el CSS crítico, o la cantidad mínima de CSS necesaria para que se renderice la página inicial, se puede alinear directamente en el <head> del documento HTML. react-snap usa otra biblioteca de terceros de forma interna, minimalcss, para extraer cualquier CSS crítico para diferentes rutas. Para habilitar esta función, especifica lo siguiente en tu archivo package.json:

"reactSnap": {
  "inlineCss": true
}

En la vista previa de la respuesta en Herramientas para desarrolladores de Chrome, ahora se mostrará la página con estilo y la integración de CSS crítica.

Una comparación del antes y el después. En la toma posterior, se muestra que el contenido se renderizó y tiene un estilo que utiliza CSS crítico intercalado.

Conclusión

Si no son rutas de renderización del servidor en tu aplicación, usa react-snap para renderizar previamente el código HTML estático para tus usuarios.

  1. Instálalo como dependencia de desarrollo y comienza solo con la configuración predeterminada.
  2. Usa la opción experimental inlineCss para intercalar el CSS crítico si funciona en tu sitio.
  3. Si usas la división de código a nivel de un componente en cualquier ruta, ten cuidado de no renderizar previamente un estado de carga para tus usuarios. El archivo react-snap README abarca esto con más detalle.