Procesamiento previo de rutas con reacción-snap

¿No usas la renderización del servidor, pero aún 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.

Esta es 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:

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 con las aplicaciones de una sola página grandes es que el usuario debe esperar a que se descarguen los paquetes de JavaScript que conforman el sitio para poder ver contenido real. Cuanto más grandes sean los paquetes, más tiempo deberá esperar el usuario.

Para resolver este problema, muchos desarrolladores adoptan el enfoque de renderizar la aplicación en el servidor en lugar de solo iniciarla 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 de primera pintura, pero a costa de un tiempo de primer byte más lento.

La renderización previa es una técnica independiente que es menos compleja que la renderización del servidor, pero también proporciona una forma de mejorar los tiempos de primera pintura en tu aplicación. Se usa un navegador sin cabeza, o un navegador 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 necesarios para la aplicación.

react-snap

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 en tu package.json:

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

Esto ejecutaría automáticamente el comando react-snap cada vez que se realice 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 el 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 usar solo ReactDOM.render para renderizar el elemento raíz de React directamente en el DOM, se verifica si ya hay nodos secundarios para determinar si el contenido HTML se renderizó previamente (o se renderizó en el servidor). Si ese es el caso, se usa ReactDOM.hydrate para adjuntar objetos de escucha de eventos al HTML ya creado en lugar de crearlo de nuevo.

La compilación de la aplicación ahora generará archivos HTML estáticos como cargas útiles para cada ruta que se rastree. Para ver 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 en las Herramientas para desarrolladores de Chrome.

Una comparación de antes y después. En la foto posterior, se muestra que se renderizó el contenido.

Flash de contenido sin diseño

Aunque el HTML estático ahora se renderiza casi de inmediato, sigue sin diseño de forma predeterminada, lo que puede causar el problema de mostrar un "flash de contenido sin diseño" (FOUC). Esto puede ser especialmente notable si usas una biblioteca de CSS en JS para generar selectores, ya que el paquete de JavaScript deberá terminar de ejecutarse antes de que se puedan aplicar los estilos.

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

"reactSnap": {
  "inlineCss": true
}

Si observas la vista previa de la respuesta en las Herramientas para desarrolladores de Chrome, ahora se mostrará la página con diseño aplicado y el CSS crítico intercalado.

Una comparación de antes y después. La foto posterior muestra que el contenido se renderizó y se le aplicó un diseño debido al CSS crítico intercalado.

Conclusión

Si no usas rutas de renderización del servidor en tu aplicación, usa react-snap para renderizar HTML estático de forma previa a tus usuarios.

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