Muchos desarrolladores han anunciado recientemente que han migrado su sitio a Astro. Esto suele ir acompañado de una captura de pantalla con una puntuación casi perfecta de Lighthouse y una serie de emojis de cohetes.
Al igual que la mayoría de la gente, el desfile interminable de nuevos frameworks me resulta agotador. Pero he jugado un poco con Astro y creo que merece la pena comprobarlo.
En este artículo, te mostraré cómo puedes construir una aplicación basada en Vue utilizando Astro y veremos cómo su arquitectura única puede conducir a un rendimiento potencialmente mejor que una aplicación de una sola página (SPA).
Recapitulación de la arquitectura de la SPA
Antes de ver Astro en acción, tendremos que entender su arquitectura. Para ello, recordemos primero los pros y los contras de la arquitectura de las aplicaciones de una sola página.
Las SPA abstraen toda la funcionalidad y el contenido de un sitio en componentes de JavaScript. Esto es genial porque facilita el desarrollo del sitio.
El inconveniente de este enfoque llega cuando el sitio se pone en producción. Todos estos componentes de JavaScript se agrupan en una gran aplicación. Debido a su tamaño, el navegador puede tardar en descargar y ejecutar la aplicación.
Por supuesto, puedes optimizar este paquete dividiendo el código. Pero seguirá habiendo un coste inicial que el navegador deberá pagar sólo para lanzar el sitio.
<!-- Una página típica de SPA -->
<head>
<script src="/app.js"></script>
</head>
<body>
<!-- Esta página no tiene contenido significativo hasta que se carga app.js -->
<div id="app"></div>
</body>
Islands architecture o Arquitectura en islas
La arquitectura en islas, utilizada por Astro, también utiliza componentes. Sin embargo, a diferencia de una aplicación de una sola página, estos componentes no se agrupan en un paquete de JavaScript.
En su lugar, cada componente se trata como una miniapp independiente que existe aislada de todas las demás.
Por ejemplo, si tu página tiene una barra de navegación con JavaScript, eso sería una miniapp. Si también tiene un carrusel de imágenes con JavaScript, será otra miniapp. Y así sucesivamente.
Pero si estos componentes no están agrupados, ¿cómo se incluyen en el proyecto? Lo explicaré en la siguiente sección.
<!-- Arquitectura en islas -->
<body>
<MyNavBar /> <!-- navbar mini app -->
<main>
<MyCarousel /> <!-- carousel mini app -->
<div class="content">
<!-- más contenido de la página... -->
</div>
</main>
</body>
Componentes renderizados por el servidor
Astro es principalmente un generador de sitios estáticos. Funciona con la mayoría de las bibliotecas de interfaz de usuario que admiten la renderización de componentes en el servidor, como Vue, Svelte, Preact, React y Lit; por cierto, si quieres ver más información sobre las bibliotecas más potentes para 2022 puedes visitar nuestro artículo 48 bibliotecas y frameworks de Javascript para el 2022.
Así, cuando Astro construye tu aplicación, cada uno de los componentes JavaScript se carga en el lado del servidor y el contenido es «instantáneo». Esta instantánea se añade a la página estática.
La renderización del servidor es una característica que no es particular de Astro, pero en las SPA es una característica opcional, mientras que en Astro es una característica crucial, como veremos a continuación.
<!-- Contenido del desarrollo -->
<body>
<MyForm /> <!-- Componente JS -->
</body>
<!-- Contenido enviado -->
<body>
<form> <!-- Componente JS renderizado por el servidor -->
<input type="text" >
<!-- ... -->
</form>
</body>
Partial Hydration o Hidratación progresiva
Aquí es donde surge la magia de Astro: mediante la combinación de la arquitectura en islas, los componentes renderizados en el servidor y la hidratación progresiva.
Como nuestra página está dividida en miniaplicaciones renderizadas en el servidor, la capa de interactividad (el JS) puede cargarse de forma independiente y sólo cuando se necesita.
Por ejemplo, puedes tener un formulario interactivo. Este formulario está más abajo en la página, fuera de la ventana gráfica.
El formulario se renderiza en el servidor, por lo que lo vemos en la página. Sin embargo, el costoso JavaScript no tendrá que cargarse hasta que el usuario lo haya desplazado a la vista.
Esto es lo que se entiende por «hidratación progresiva» en Astro, algo así parecido al típico lazy load de las imágenes: sólo cargamos el JavaScript a medida que se necesita, cuando se necesita.
Configurar un proyecto Vue + Astro
Ahora que la teoría está fuera del camino, ¡vamos a verlo en acción!
Para empezar a crear un proyecto Astro, primero crearemos un directorio:
$ mkdir vue-astro
A continuación, ejecuta el asistente de instalación de Astro:
$ npm init astro
El asistente de instalación nos permitirá seleccionar «Vue» como nuestro framework elegido. Esto creará un proyecto boilerplate que incluirá componentes Vue.
Componentes Astro
Las páginas Astro se guardan en el directorio src/pages. En una instalación por defecto, vemos un archivo index.astro, que se muestra a continuación.
---
import VueCounter from '../components/VueCounter.vue';
let title = 'My Astro Site';
---
<html lang="en">
<head>
<!-- ... -->
<title>{title}</title>
</head>
<body>
<main>
<!-- ... -->
<VueCounter client:visible />
</main>
</body>
</html>
Astro tiene un estilo de componente de un solo archivo, como Vue, pero con algunas diferencias importantes.
En primer lugar, en la parte superior del archivo, vemos lo que parece ser frontmatter, es decir, el contenido delimitado con —. Este es el JavaScript que se ejecuta en el lado del servidor. No se envía al cliente.
Aquí podemos ver dos cosas importantes: en primer lugar, estamos importando un componente Vue (aquí puedes importar componentes de cualquier framework compatible). Además, estamos estableciendo un valor, title.
Todas las variables declaradas aquí están disponibles en la plantilla. Verás que el título se interpola en la plantilla con una sintaxis similar a la de JSX.
---
...
let title = 'My Astro Site';
---
<html lang="en">
<head>
<!-- ... -->
<title>{title}</title>
</head>
<!-- ... -->
A continuación, observa que el componente declarado en la plantilla.
Por defecto, los componentes no son interactivos en el cliente y simplemente son renderizados por el servidor por Astro.
Si queremos que un componente sea interactivo, es decir, que cargue el JavaScript, tenemos que darle una directiva que indique al cliente cuándo debe cargarlo.
En este caso, la directiva client:visible indica a Astro que haga que VueCounter sea interactivo cuando el componente sea visible en la página.
Cuando esto ocurra, Astro solicitará el JS de este componente al servidor y lo hidratará.
---
import VueCounter from '../components/VueCounter.vue';
...
---
<html lang="en">
<head><!-- ... --></head>
<body>
<main>
<!-- ... -->
<VueCounter client:visible />
</main>
</body>
</html>
Cargando Astro
Ahora vamos a ejecutar el servidor de desarrollo de Astro para ver nuestro proyecto.
npm run dev
En el código fuente de la página verás que no hay ningún paquete de JavaScript en el documento. Sin embargo, sí vemos el componente Vue renderizado en el servidor.
También vemos que Astro ha añadido un script en la parte inferior del cuerpo del documento. Aquí carga un módulo que hidrata el componente Vue.
Este módulo descargará tanto el componente Vue como las dependencias (el framework Vue) sin bloquear el renderizado.
<!-- Page source -->
<body>
<!-- server rendered component -->
<div id="vue" class="counter">
<button>-</button>
<pre>0</pre>
<button>+</button>
</div>
<!-- snippet added to hydrate the Vue component -->
<script type="module">
import setup from '/_astro_frontend/hydrate/visible.js';
// ...
</script>
Por qué Vue + Astro puede ser mejor que Vue SPA
Para ver por qué Astro puede superar a una aplicación de una sola página en términos de UX, hagamos un desglose simplificado de lo que ocurre cuando se carga el sitio.
- Se carga index.html. No tiene ningún paquete de JS, pero incluye tus componentes renderizados por el servidor, de modo que el usuario ya puede ver el contenido de tu sitio, sólo que aún no es interactivo.
- Cualquier JS que sea necesario para los componentes se descargará ahora de forma asíncrona como una serie de scripts independientes.
- Una vez descargados estos scripts, serán analizados y ejecutados. Ahora la interactividad está disponible.
Ahora imaginemos que reconstruimos este sitio como una aplicación de una sola página. ¿Cómo se cargaría ahora?
- Se carga index.html. Como la página no tiene contenido, el usuario no puede ver nada. El navegador comenzará a descargar el paquete.
- Una vez descargado el paquete JS, el navegador lo analiza. El usuario sigue sin poder ver nada.
- Una vez analizado y ejecutado el paquete JS, se genera el contenido de la página. El usuario ya puede ver e interactuar con la aplicación.
Resumiendo: el sitio Astro proporcionará contenido visible casi de inmediato, a diferencia de la SPA, que necesita descargar y ejecutar primero un paquete JS.
(La aplicación Astro también proporcionará interactividad un poco antes, ya que probablemente no necesite descargar tanto JS al no haber un shell SPA, un router, etc.)
Conclusión
La arquitectura de Astro puede ser una mejor opción que una aplicación de una sola página, ya que hace visible el contenido sin JavaScript y sólo carga el JS cuando lo necesita.
En teoría, una aplicación de una sola página puede lograr algo similar mediante una combinación de prerrenderización y división del código. La diferencia es que los sitios Astro están optimizados de esta manera por defecto, ya que tienes que optar por la interactividad y el JS.
Por ello, la gente obtiene puntuaciones de Lighthouse de forma inmediata.
Por supuesto, no todas las aplicaciones se beneficiarán de esta arquitectura, ya que las SPA se adaptan mejor a ciertos tipos de aplicaciones, por ejemplo, las altamente dinámicas e interactivas. Así que no esperemos que la arquitectura SPA desaparezca.
Deja una respuesta