Headless WordPress con Frontity, React y WordPress.com
En mayo de 2020 decidí dar un paso que llevaba pensando desde 2019: Mover mi blog en WordPress.com a otro sitio y crear un tema de WordPress hecho con React. Como mi tiempo es muy reducido últimamente (👶 ), necesito gestionarlo al límite si quiero sacar proyectos personales y crear un tema en React desde cero no era algo trivial. En esto que en 2019 aparece Frontity, un framework de React especialmente diseñado para trabajar con WordPress. Es sencillo de configurar y desplegar, aunque hay que aprender varios conceptos nuevos.
Si necesitas ver el código de toda la web, lo tienes en GitHub.
Mi plan
Mi plan era que no tenía plan pero sí estaba seguro de querer seguir ciertas pautas:
- El sitio debería estar funcionando (que no terminado) en menos de 10 días en mis ratos libres.
- Si me atasco en un concepto que me empieza a llevar demasiado tiempo, doy un paso atrás y opto por la opción más cutre pero más rápida. Ya habrá tiempo de cambiarlo una vez la web esté operativa (si es que merece la pena).
- El sitio debería funcionar con mi sitio en WordPress.com
- Debería ser sencillo y que no cargue demasiadas cosas.
- Que siga la paleta de colores de mi IDE, PhpStorm (Uso el tema Dark Theme).
- El código cerdo está permitido.
¿Cómo funciona Frontity?
Frontity es un framework para React especialmente diseñado para crear sitios con WordPress. Consume de la REST API de una instalación cualquiera de WordPress y genera parte del HTML con node, usando una técnica muy común últimamente: Server Side Rendering (SSR). Este HTML se envía al navegador, y éste se encarga de renderizar el resto con React (JavaScript). Esta parte del renderizado puede consistir en una serie de áreas del sitio web que no son críticas o prioritarias. Como ejemplo, en este ilustre sitio, el banner con mi foto se carga una vez el HTML ha llegado al navegador. Éste hace un fetch a la REST API y pinta ese banner de forma asíncrona.
Todo esto ya existía en realidad, y de hecho si has desarrollado alguna vez algo en PHP, sea un Tema en WordPress o cualquier otra cosa, ya has utilizado SSR (PHP genera el HTML y lo envía al navegador y éste carga JS para añadir interactividad o pintar áreas que no eran prioritarias). Lo que pasa es que hacerlo con PHP y JavaScript era mucho más complicado y ahora, con node y React, puesto que ambos utilizan JavaScript, se puede hacer de una manera más ordenada.
Ventajas de usar Frontity
Hay varias. Primero, que es rapidísimo de instalar y empezar con él, en cuestión de minutos tenía ya la web funcionando. Además, es un framework que está preparado exclusivamente para WordPress; esto con otros frameworks similares como Next.js no ocurre, ya que estos tratan de ser más generalistas.
Con Frontity, casi te tienes que olvidar del modelo de datos o de conectar con la REST API. Todo lo gestiona internamente de manera eficiente y sólo queda desarrollar un tema para Frontity con una serie de componentes en React. A ver, que no es poco, no nos confundamos tampoco, pero hacerlo mediante otro framework puede ser una tarea muy larga. Frontity evita lo más complicado al empezar con un proyecto de node o React: La configuración del entorno de desarrollo y el modelado de los datos que vienen a través de la REST API.
Por último, tiene la gran ventaja de que también funciona con sitios de WordPress.com, como el caso de este sitio. Para utilizar la REST API de WordPress.com sólo hay que cambiar una línea en el frontity.settings.js
:
...
state: {
source: {
api:
'https://public-api.wordpress.com/wp/v2/sites/igmoweb.com',
},
},
...
Frontity es extensible
Simplificando mucho muchísimo, Frontity genera algo así:
<html>
<head>
${head.title || ""}
</head>
<body>
<div id="root">${html}</div>
${frontity.script || ""}
</body>
</html>
Todo lo que va entre ${}
es JavaScript embebido en el HTML y que Frontity se encargará de llenar. Aunque hay más, creo que con lo que se ve ahí es suficiente para entender más o menos cómo funciona. Cuando alguien visita la web, node recoge este HTML (que es un fichero TypeScript), digamos que “llama” a React para que éste le envíe el contenido, ya en formato HTML, para rellenar los huecos. Estos huecos, en el código que acabo de poner, son:
head.title
: El título de la página actual.html
: Todo el HTML dentro delbody
. Vamos, la chicha de verdad.frontity.scripts
: Se sustituirá por scripts que Frontity utiliza.
Durante este proceso, React se ejecuta, pinta el HTML en el servidor y se envía al cliente con lo que éste recibe una web completa sin necesidad de pintar nada con JS. Pero esto lo podemos cambiar a nuestro antojo mediante el Code Splitting, del que hablo más adelante.
Lo que hace de Frontity una herramienta potente es su extensibilidad. Frontity hace uso de lo que llaman ellos Roots and Fills, una técnica que se basa en una librería llamada react-slot-fill y en la que, oh, también Gutenberg se inspira. Frontity pone a disposición del desarrollador una serie de Roots y nosotros enviamos nuestros componentes para rellenar esos huecos (Fills).
Packages
Esto daría para otro post pero voy a intentar resumirlo. Para generar componentes y rellenar esos Roots, Frontity trabaja con paquetes: Un tema es un paquete pero un plugin de Frontity también lo es. Cada paquete lo que hace es insertar componentes en distintos Roots.
Por ejemplo, un tema Hola Mundo:
export default {
roots: {
theme: () => {
return <div>Hola Mundo</div>
}
}
}
Esto va a insertar un nodo, <div>Hola Mundo</div>
en el root del body. Sí, ese que tenía un ${html}
dentro, con lo que ese html
será sustituido por dicho nodo. Es más, si quisiéramos podríamos tener ¡Otro tema! enviando otro nodo a dicho root. Frontity no sustituiría uno por otro, sino que añadiría ambos nodos.
Para añadir un título dentro de ${head.title}
tendríamos que utilizar un componente especial de Frontity dentro de nuestro tema
import { Head } from 'frontity';
...
<Head>
<title>Título de prueba</title>
</Head>
Frontity ya se encarga de insertar ese `<title>` dentro de la cabecera.
Con esto podemos conseguir un proyecto totalmente modularizado. Podríamos tener un paquete para el tema, otro para el título, otro para, no sé, un formulario de contacto. Y además podemos publicarlos como paquetes de npm y reutilizarlos en más proyectos. A mí esta parte me hace babear porque tiene muchas posibilidades.
Esto carga rápido
Una vez instalado Frontity, lo primero de lo que nos percatamos es que la página vuela. Node es rápido renderizando y Frontity gestiona bien las llamadas a la REST API, es muy eficiente. Además, al utilizar CSS In JS, la página sólo utilizará el CSS que realmente se requiere para pintarla. A mí CSS In JS no me termina de convencer, creo que es un buen lío a la hora de programar y que requiere un orden muy especial pero también acabo de empezar a aprender así que le daré un tiempo. De todas formas, Frontity no da otra opción (olvídate de Sass), lo cual es un poco fastidioso.
A día 20 de mayo, esto era lo que cargaba la web:
483kb de bundle principal. Aquí va todo el JS y CSS en realidad pero para una primera carga me parecía grande. Las primera flecha roja es una carga asíncrona del banner principal donde pone Hola, Soy Ignacio (Esto es otra página en WordPress con su título y contenido). De esta forma, el contenido se carga más tarde y muestra un GIF mientras tanto.
Algo que puede lanzar tu página a velocidades cercanas a la de la luz, es la capacidad de prefetching que tienes con Frontity. En cualquier momento le puedes decir a Frontity que te vaya cargando tal o cual página, o el siguiente post, o todas las páginas que hay en el menú de navegación, de tal forma que si el usuario hace click en uno de esos enlaces, el contenido ya está preparado para servir y la redirección es inmediata. La diferencia entre esto y recargar la página es abismal. Esto es el caso de la segunda flecha roja. Es decir, nada más cargar la web, se inicia una precarga de la siguiente página (me refiero a la paginación de los posts) y si el usuario hiciera click en la siguiente página, la carga sería inmediata. En realidad, todos los enlaces internos hacen una precarga cuando se pasa el ratón por encima de ellos.
Code Splitting
El bundle principal seguía siendo muy grande para una primera carga; era hora ya de empezar a dividir el bundle en trozos más pequeños. La idea es tener un bundle principal donde se cargue lo necesario y luego ir cargando partes de la web por detrás sin que el usuario lo note y sólo cuando sea necesario. Para ello utilizamos el Code Splitting
Yo he utilizado esta técnica con varios componentes: El banner donde me presento, el componente del listado de posts y el componente que se utiliza para renderizar código.
El del banner en realidad no tiene mucho sentido separarlo y creo que volveré a dejarlo en el bundle principal pero lo hice por probar. El del listado de posts parece que tampoco pero es que en realidad yo espero que los visitantes no entren por ahí sino a través de alguno de mis artículos. El que de verdad ahorra espacio sin embargo es el que contiene la librería para renderizar trozos de código con formato. Cuando lo separé me di cuenta de que la mitad del bundle principal se lo quedaba la librería highlight.js. Aquí hay un ejemplo de los distintos archivos JS que se cargan cuando visito un post que tiene código:
Fijaos en la diferencia: El bundle principal tiene ahora 237kb y el highlited-code
260kb y este último sólo se carga cuando visitas un post con código con lo que estamos ahorrando bastante carga en principio. La única pega es que, claro, si esto es un blog sobre desarrollo pues oye, lo voy a necesitar casi siempre pero es interesante dividir código de cualquier forma.
Por cierto, para separar este código también tuve que usar processors en Frontity, que es una manera que tiene de parsear el contenido de los posts. Primero hay que detectar qué nodos tienen código y luego cargar el componente y la librería para formatear dicho código. Esta parte no es la más fácil del proyecto y explicarlo tomaría tiempo pero el código de los processors que utilizo está aquí: https://github.com/igmoweb/igmoweb.com/tree/master/packages/igmoweb-theme/src/processors
Despliegue
Estoy utilizando Vercel para ejecutar el servidor de node que Frontity arranca. Vercel es el hosting que recomiendan desde Frontity y no tengo nada negativo que decir sobre él, estoy absolutamente encantado y es lo mejor que he probado en mi vida en cuanto a despliegues. Sencillísimo de usar, rapidísimo y para proyectos personales es gratis. El despliegue se puede hacer mediante comandos de npm pero lo mejor es integrarlo con GitHub: Por cada Pull Request que hagas, te genera una URL en la que puedes probar ese PR antes de hacer el merge en master
. Fino, finísimo. Lo mejor es probarlo.
¿Y ahora qué?
Hay muchas cosas que faltan por hacer y Frontity todavía es un proyecto relativamente joven pero que ya tiene la atención e inversión de Automattic por lo que hay que estar preparados para que el proyecto mejore en los próximos meses. Para mí sería esencial que se pudiera extender el propio servidor de node y no sólo lo que se ve a pintar en el front. Esto abriría muchas puertas para autenticación, AMP, RSS, procesado de formularios y otras muchas cosas. Sé que ya están trabajando en ello así que espero que pronto puedan anunciar novedades.