Construyendo el SSG que siempre quise: un sándwich 11ty, Vite y JAM
Publicado: 2022-03-10No sé ustedes, pero me he sentido abrumado por todas las herramientas de desarrollo web que tenemos en estos días. Ya sea que le guste Markdown, HTML simple, React, Vue, Svelte, plantillas Pug, Handlebars, Vibranium, probablemente pueda mezclarlo con algunos datos de CMS y obtener un buen cóctel de sitio estático.
No voy a decirle qué herramientas de desarrollo de interfaz de usuario debe utilizar porque todas son excelentes, según las necesidades de su proyecto. Esta publicación trata sobre cómo encontrar el generador de sitios estáticos perfecto para cualquier ocasión; algo que nos permite usar plantillas sin JS como Markdown para comenzar, y traer "islas" de interactividad basada en componentes según sea necesario.
Estoy destilando el valor de un año de aprendizajes en una sola publicación aquí. No solo vamos a hablar de código (también conocido como unir 11ty y Vite con cinta adhesiva), sino que también vamos a explorar por qué este enfoque es tan universal para los problemas jamstackianos. Tocaremos:
- Dos enfoques para la generación de sitios estáticos y por qué debemos cerrar la brecha;
- Donde los lenguajes de plantillas como Pug y Nunjucks todavía resultan útiles;
- Cuándo deben entrar en juego marcos de componentes como React o Svelte;
- Cómo el nuevo mundo de recarga en caliente de Vite nos ayuda a llevar la interactividad de JS a nuestro HTML con casi cero configuraciones;
- Cómo esto complementa la cascada de datos de 11ty, trayendo datos CMS a cualquier marco de componentes o plantilla HTML que pueda desear.
Entonces, sin más preámbulos, aquí está mi historia de scripts de compilación terribles, avances de paquetes y cinta adhesiva de código de espagueti que (eventualmente) me dio el SSG que siempre quise: ¡un sándwich 11ty, Vite y Jam llamado Slinkity!
Una gran brecha en la generación de sitios estáticos
Antes de sumergirme, quiero discutir lo que llamaré dos "campos" en la generación de sitios estáticos.
En el primer campo, tenemos el generador de sitio estático “simple”. Estas herramientas no traen paquetes de JavaScript, aplicaciones de una sola página y cualquier otra palabra de moda que esperamos. Simplemente clavan los fundamentos de Jamstack: extraen datos de cualquier blob JSON de CMS que prefieras y deslizan esos datos en plantillas HTML simples + CSS. Herramientas como Jekyll, Hugo y 11ty dominan este campamento, permitiéndole convertir un directorio de archivos Markdown y Liquid en un sitio web totalmente funcional. Beneficios clave:
- curva de aprendizaje poco profunda
Si sabes HTML, ¡estás listo para comenzar! - Tiempos de construcción rápidos
No estamos procesando nada complejo, por lo que cada ruta se construye en un abrir y cerrar de ojos. - Tiempo instantáneo a interactivo
No hay (o muy poco) JavaScript para analizar en el cliente.
Ahora, en el segundo campo, tenemos el generador de sitios estáticos "dinámicos". Estos introducen marcos de componentes como React, Vue y Svelte para brindar interactividad a su Jamstack. Estos cumplen la misma promesa central de combinar datos CMS con las rutas de su sitio en el momento de la construcción. Beneficios clave:
- Creado para la interactividad
¿Necesitas un carrusel de imágenes animadas? ¿Formulario de varios pasos? Simplemente agregue una pepita dividida en componentes de HTML, CSS y JS. - Administración del Estado
Algo como React Context de las tiendas Svelte permite compartir datos sin problemas entre rutas. Por ejemplo, el carrito en su sitio de comercio electrónico.
Hay distintas ventajas para cualquiera de los dos enfoques. Pero, ¿qué sucede si elige un SSG del primer campamento como Jekyll, solo para darse cuenta de que, seis meses después de su proyecto, necesita algo de interactividad de componentes? ¿O elige algo como NextJS para esos componentes poderosos, solo para luchar con la curva de aprendizaje de React, o KB innecesarios de JavaScript en una publicación de blog estática?
En mi opinión, pocos proyectos encajan perfectamente en un campo u otro. Existen en un espectro, favoreciendo constantemente nuevos conjuntos de funciones a medida que evolucionan las necesidades de un proyecto. Entonces, ¿cómo podemos encontrar una solución que nos permita comenzar con las herramientas simples del primer campo y agregar gradualmente características del segundo cuando las necesitemos?
Bueno, repasemos un poco mi viaje de aprendizaje.
Nota: Si ya está convencido de las plantillas estáticas con 11ty para crear sus sitios estáticos, siéntase libre de pasar al tutorial de código jugoso.
Pasando de componentes a plantillas y API web
En enero de 2020, me propuse hacer lo que casi todos los desarrolladores web hacen cada año: reconstruir mi sitio personal. Pero esta vez iba a ser diferente. Me desafié a mí mismo a construir un sitio con las manos atadas a la espalda, ¡no se permiten marcos ni canalizaciones de construcción!
Esta no fue una tarea sencilla como devoto de React. Pero con la cabeza en alto, me dispuse a construir mi propio canal de construcción desde cero. Hay mucho código mal escrito que podría compartir de la versión 1 de mi sitio personal... pero te dejaré hacer clic en este LÉAME si eres tan valiente. En su lugar, quiero centrarme en los aprendizajes de alto nivel que aprendí privándome de mis placeres culpables de JS.
Las plantillas van mucho más allá de lo que piensas
Llegué a este proyecto como un adicto a la recuperación de JavaScript. Hay algunas necesidades relacionadas con el sitio estático que me encantó usar marcos basados en componentes para llenar:
- Queremos dividir mi sitio en componentes de interfaz de usuario reutilizables que puedan aceptar objetos JS como parámetros (también conocidos como "accesorios").
- Necesitamos obtener cierta información en el momento de la compilación para colocarla en un sitio de producción.
- Necesitamos generar un montón de rutas URL desde un directorio de archivos o un objeto de contenido JSON grueso.
Lista extraída de este post de mi blog personal.
Pero es posible que hayas notado que ninguno de estos realmente necesita JavaScript del lado del cliente. Los marcos de componentes como React están diseñados principalmente para manejar las preocupaciones de administración del estado, como la aplicación web de Facebook que inspiró a React en primer lugar. Si solo está dividiendo su sitio en componentes pequeños o elementos del sistema de diseño, ¡las plantillas como Pug también funcionan bastante bien!
Tome esta barra de navegación, por ejemplo. En Pug, podemos definir un "mixin" que recibe datos como accesorios:
// nav-mixins.pug mixin NavBar(links) // pug's version of a for loop each link in links a(href=link.href) link.text
Luego, podemos aplicar esa combinación en cualquier parte de nuestro sitio.
// index.pug // kinda like an ESM "import" include nav-mixins.pug html body +NavBar(navLinksPassedByJS) main h1 Welcome to my pug playground
Si "renderizamos" este archivo con algunos datos, obtendremos un hermoso index.html
para servir a nuestros usuarios.
const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] }) // use the NodeJS filesystem helpers to write a file to our build await writeFile('build/index.html', html)
Claro, esto no ofrece sutilezas como CSS con alcance para tus mixins, o JavaScript con estado donde lo desees. Pero tiene algunos beneficios muy poderosos sobre algo como React:
- No necesitamos empaquetadores sofisticados que no entendemos.
Acabamos de escribir esa llamadapug.render
a mano y ya tenemos la primera ruta de un sitio lista para implementar. - No enviamos ningún JavaScript al usuario final.
El uso de React a menudo significa enviar un tiempo de ejecución grande y antiguo para que se ejecuten los navegadores de las personas. Al llamar a una función comopug.render
en el momento de la compilación, mantenemos todo el JS de nuestro lado mientras enviamos un archivo.html
limpio al final.
Es por eso que creo que las plantillas son una gran "base" para sitios estáticos. Aún así, sería bueno poder llegar a marcos de componentes donde realmente nos beneficiemos de ellos. Más sobre eso más adelante.
Lectura recomendada : Cómo crear mejores plantillas angulares con Pug por Zara Cooper
No necesita un marco para crear aplicaciones de una sola página
Mientras estaba en eso, también quería algunas transiciones de página atractivas en mi sitio. Pero, ¿cómo logramos algo como esto sin un marco?
Bueno, no podemos hacer esto si cada página es su propio archivo .html
. Todo el navegador se actualiza cuando saltamos de un archivo HTML a otro, por lo que no podemos tener ese agradable efecto de fundido cruzado (ya que mostraríamos brevemente ambas páginas una encima de la otra).
Necesitamos una forma de "obtener" el HTML y el CSS de donde sea que estemos navegando, y animarlos a la vista usando JavaScript. ¡Esto suena como un trabajo para aplicaciones de una sola página! Utilicé una combinación simple de API de navegador para esto:
- Intercepte todos los clics de su enlace utilizando un detector de eventos.
- fetch API : obtenga todos los recursos para cualquier página que desee visitar y tome la parte que quiero animar a la vista: el contenido fuera de la barra de navegación (que quiero que permanezca estacionario durante la animación).
- API de animaciones web : anime el nuevo contenido a la vista como un fotograma clave.
- API de historial : cambie la ruta que se muestra en la barra de URL de su navegador usando
window.history.pushState({}, 'new-route')
. De lo contrario, ¡parece que nunca dejaste la página anterior!
Para mayor claridad, aquí hay una ilustración visual de ese concepto de aplicación de una sola página usando un simple buscar y reemplazar ( artículo fuente ):
Nota : También puede visitar el código fuente desde mi sitio personal.
Claro, algún emparejamiento de React et al y su biblioteca de animación de elección puede hacer esto. Pero para un caso de uso tan simple como una transición gradual... las API web son bastante poderosas por sí mismas. Y si desea transiciones de página más sólidas en plantillas estáticas como Pug o HTML simple, las bibliotecas como Swup le servirán bien.
Lo que 11ty trajo a la mesa
Me sentía bastante bien con mi pequeño SSG en este momento. Claro que no pudo obtener ningún dato de CMS en el momento de la compilación, y no admitió diferentes diseños por página o por directorio, y no optimizó mis imágenes y no tenía compilaciones incrementales.
Está bien, podría necesitar algo de ayuda.
Teniendo en cuenta todo lo que aprendí de la versión 1, pensé que me había ganado el derecho de abandonar la regla de "sin canalizaciones de compilación de terceros" y buscar las herramientas existentes. ¡Resulta que 11ty tiene un tesoro de características que necesito!
- Obtención de datos en tiempo de compilación utilizando archivos
.11ydata.js
; - Datos globales disponibles para todas mis plantillas desde una carpeta
_data
; - Recarga en caliente durante el desarrollo usando browsersync;
- Compatibilidad con transformaciones HTML sofisticadas;
- ... y un sinnúmero de otras cosas.
Si ha probado SSG básicos como Jekyll o Hugo, debería tener una idea bastante clara de cómo funciona 11ty. ¿Única diferencia? 11ty usa JavaScript de principio a fin.
11ty es compatible básicamente con todas las bibliotecas de plantillas que existen, por lo que estaba feliz de representar todas mis páginas de Pug en rutas .html
. Su opción de encadenamiento de diseño también ayudó con mi configuración de aplicación de una sola página falsa. Solo necesitaba un solo script
para todas mis rutas y un diseño "global" para importar ese script:
// _includes/base-layout.html <html> <body> <!--load every page's content between some body tags--> {{ content }} <!--and apply the script tag just below this--> <script src="main.js"></script> </body> </html> // random-blog-post.pug --- layout: base-layout --- article h2 Welcome to my blog p Have you heard the story of Darth Plagueis the Wise?
Siempre que main.js
haga toda la intercepción de enlaces que exploramos, ¡tendremos transiciones de página!
Ah, y la cascada de datos
Así que 11ty me ayudó a limpiar todo mi código espagueti de v1. Pero trajo otra pieza importante: una API limpia para cargar datos en mis diseños. Este es el pan y la mantequilla del enfoque Jamstack. En lugar de obtener datos en el navegador con la manipulación de JavaScript + DOM, puede:
- Obtener datos en tiempo de compilación mediante Node.
Esto podría ser una llamada a alguna API externa, una importación local de JSON o YAML, o incluso el contenido de otras rutas en su sitio (imagine actualizar una tabla de contenido cada vez que se agregan nuevas rutas). - Inserte esos datos en sus rutas. Recuerda la función
.render
que escribimos anteriormente:
const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] })
…pero en lugar de llamar a pug.render
con nuestros datos cada vez, dejamos que 11ty haga esto entre bastidores.
Claro, no tenía muchos datos para mi sitio personal. Pero fue genial crear un archivo .yaml
para todos mis proyectos personales:
# _data/works.yaml - title: Bits of Good Homepage hash: bog-homepage links: - href: https://bitsofgood.org text: Explore the live site - href: https://github.com/GTBitsOfGood/bog-web text: Scour the Svelt-ified codebase timeframe: May 2019 - present tags: - JAMstack - SvelteJS - title: Dolphin Audio Visualizer ...
Y acceda a esos datos en cualquier plantilla:
// home.pug .project-carousel each work in works h3 #{title} p #{timeframe} each tag in tags ...
Viniendo del mundo de la "representación del lado del cliente" con la aplicación create-react, esta fue una gran revelación. No más enviar claves API o grandes blobs JSON al navegador.
También agregué algunas ventajas para la recuperación de JavaScript y mejoras en la animación sobre la versión 1 de mi sitio. Si tiene curiosidad, aquí es donde estaba mi LÉAME en este momento.
Estaba feliz en este punto, pero faltaba algo
Llegué sorprendentemente lejos al abandonar los componentes basados en JS y adoptar plantillas (con transiciones de página animadas para arrancar). Pero sé que esto no satisfará mis necesidades para siempre. ¿Recuerdas esa gran división con la que nos pateamos? Bueno, claramente todavía existe ese desfiladero entre mi configuración de compilación (firmemente en el campo n.° 1) y el refugio de la interactividad JS-ified (Next, SvelteKit y más del campo n.° 2). Di que quiero agregar:
- un modal emergente con una palanca de abrir/cerrar,
- un sistema de diseño basado en componentes como Material UI, completo con estilo de ámbito,
- una forma compleja de varios pasos, tal vez impulsada por una máquina de estado.
Si eres un purista de JS simple, probablemente tengas respuestas sin marco para todos esos casos de uso. ¡Pero hay una razón por la que JQuery ya no es la norma! Hay algo atractivo en la creación de componentes discretos y fáciles de leer de HTML, estilos de alcance y piezas de variables de "estado" de JavaScript. React, Vue, Svelte, etc. ofrecen tantas sutilezas para depurar y probar que la manipulación DOM directa no puede igualar.
Así que aquí está mi pregunta del millón de dólares:
¿Podemos usar plantillas HTML directas para comenzar y agregar gradualmente componentes React/Vue/Svelte donde los queremos?
La respuesta es sí . Vamos a intentarlo.
11ty + Vite: Una pareja hecha en el cielo ️
Aquí está el sueño que estoy imaginando aquí. Siempre que quiera insertar algo interactivo, quiero dejar una pequeña bandera en mi plantilla para "poner el componente X React aquí". Esta podría ser la sintaxis de shortcode que admite 11ty:
# Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react './components/FancyLiveDemo.jsx' %}
Pero recuerde, el 11ty de una sola pieza (a propósito) evita: una forma de agrupar todo su JavaScript. Viniendo del gremio OG de la agrupación, su cerebro probablemente salta a la construcción de procesos Webpack, Rollup o Babel aquí. Cree un archivo de punto de entrada grande y antiguo y genere un hermoso código optimizado, ¿verdad?
Bueno, sí, pero esto puede ser bastante complicado. Si usamos componentes de React, por ejemplo, probablemente necesitemos algunos cargadores para JSX, un elegante proceso de Babel para transformar todo, un intérprete para las importaciones de módulos SASS y CSS, algo que ayude con la recarga en vivo, etc.
Si tan solo hubiera una herramienta que pudiera ver nuestros archivos .jsx
y saber exactamente qué hacer con ellos.
Ingrese: Vite
Vite ha sido la comidilla de la ciudad últimamente. Está destinado a ser la herramienta todo en uno para construir casi cualquier cosa en JavaScript. Aquí tienes un ejemplo para que pruebes en casa. Hagamos un directorio vacío en algún lugar de nuestra máquina e instalemos algunas dependencias:
npm init -y # Make a new package.json with defaults set npm i vite react react-dom # Grab Vite + some dependencies to use React
Ahora, podemos crear un archivo index.html
para que sirva como "punto de entrada" de nuestra aplicación. Lo mantendremos bastante simple:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> </body> </html>
Lo único interesante es que div id="root"
en el medio. ¡Esta será la raíz de nuestro componente React en un momento!
Si lo desea, puede iniciar el servidor Vite para ver nuestro archivo HTML sin formato en su navegador. Simplemente ejecute vite
(o npx vite
si el comando no se configuró en su terminal) y verá este útil resultado:
vite vX.XX dev server running at: > Local: http://localhost:3000/ > Network: use `--host` to expose ready in Xms.
Al igual que Browsersync u otros servidores de desarrollo populares, el nombre de cada archivo .html
corresponde a una ruta en nuestro servidor. Entonces, si cambiamos el nombre de index.html
a about.html
, visitaríamos http://localhost:3000/about/
(sí, ¡necesitarás una barra inclinada al final!)
Ahora hagamos algo interesante. Junto con ese archivo index.html
, agregue un componente React básico de algún tipo. Usaremos useState
de React aquí para demostrar la interactividad:
// TimesWeMispronouncedVite.jsx import React from 'react' export default function TimesWeMispronouncedVite() { const [count, setCount] = React.useState(0) return ( <div> <p>I've said Vite wrong {count} times today</p> <button onClick={() => setCount(count + 1)}>Add one</button> </div> ) }
Ahora, carguemos ese componente en nuestra página. Esto es todo lo que tenemos que agregar a nuestro index.html
:
<!DOCTYPE html> ... <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> <!--Don't forget type="module"! This lets us use ES import syntax in the browser--> <script type="module"> // path to our component. Note we still use .jsx here! import Component from './TimesWeMispronouncedVite.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('root'); ReactDOM.render(React.createElement(Component), componentRoot); </script> </body> </html>
Sí, eso es todo. ¡No es necesario transformar nuestro archivo .jsx
en un archivo .js
listo para el navegador nosotros mismos! Siempre que Vite vea una importación .jsx
, convertirá automáticamente ese archivo a algo que los navegadores puedan entender. Ni siquiera hay una carpeta dist
o build
cuando se trabaja en desarrollo; Vite procesa todo sobre la marcha, completo con la recarga activa del módulo cada vez que guardamos nuestros cambios.
Bien, entonces tenemos una herramienta de compilación increíblemente capaz. ¿Cómo podemos llevar esto a nuestras plantillas 11ty?
Ejecutando Vite junto a 11ty
Antes de pasar a lo bueno, analicemos la ejecución de 11ty y Vite en paralelo. Continúe e instale 11ty como una dependencia de desarrollo en el mismo directorio del proyecto de la última sección:
npm i -D @11ty/eleventy # yes, it really is 11ty twice
Ahora hagamos una pequeña verificación previa al vuelo para ver si 11ty funciona. Para evitar cualquier confusión, te sugiero:
- Elimine ese archivo
index.html
de antes; - Mueva ese
TimesWeMispronouncedVite.jsx
dentro de un nuevo directorio. Digamos,components/
; - Cree una carpeta
src
para que viva nuestro sitio web; - Agregue una plantilla a ese directorio
src
para que 11ty la procese.
Por ejemplo, un archivo blog-post.md
con los siguientes contenidos:
# Hello world! It's markdown here
La estructura de su proyecto debería verse así:
src/ blog-post.md components/ TimesWeMispronouncedVite.jsx
Ahora, ejecute 11ty desde su terminal así:
npx eleventy --input=src
Si todo va bien, debería ver un resultado de compilación como este:
_site/ blog-post/ index.html
Donde _site
es nuestro directorio de salida predeterminado y blog-post/index.html
es nuestro archivo de rebajas bellamente convertido para navegar.
Normalmente, ejecutaríamos npx eleventy --serve
para poner en marcha un servidor de desarrollo y visitar esa página /blog-post
. ¡Pero estamos usando Vite para nuestro servidor de desarrollo ahora! El objetivo aquí es:
- Haz que eleventy construya nuestro markdown, Pug, nunjucks y más en el directorio
_site
. - Apunte a Vite en ese mismo directorio
_site
para que pueda procesar los componentes de React, las importaciones de estilos sofisticados y otras cosas que 11ty no detectó.
Entonces, un proceso de construcción de dos pasos, con 11ty entregando el Vite. Aquí está el comando CLI que necesitará para iniciar 11ty y Vite en modo "ver" simultáneamente:
(npx eleventy --input=src --watch) & npx vite _site
También puede ejecutar estos comandos en dos terminales separados para facilitar la depuración.
Con un poco de suerte, debería poder visitar http://localhost:3000/blog-post/
(de nuevo, ¡no olvide la barra diagonal final!) para ver el archivo Markdown procesado.
Hidratación parcial con códigos cortos
Hagamos un breve resumen de los shortcodes. Es hora de revisar esa sintaxis de antes:
{% react '/components/TimesWeMispronouncedVite.jsx' %}
Para aquellos que no están familiarizados con los códigos abreviados: son casi lo mismo que una llamada de función, donde la función devuelve una cadena de HTML para deslizarse en su página. La "anatomía" de nuestro shortcode es:
-
{% … %}
Envoltorio que indica el inicio y el final del shortcode. -
react
El nombre de nuestra función de shortcode lo configuraremos en un momento. -
'/components/TimesWeMispronouncedVite.jsx'
El primer (y único) argumento de nuestra función shortcode. Puedes tener tantos argumentos como quieras.
¡Conectemos nuestro primer shortcode! Agregue un archivo .eleventy.js
a la base de su proyecto y agregue esta entrada de configuración para nuestro shortcode de react
:
// .eleventy.js, at the base of the project module.exports = function(eleventyConfig) { eleventyConfig.addShortcode('react', function(componentPath) { // return any valid HTML to insert return `<div>This is where we'll import ${componentPath}</div>` }) return { dir: { // so we don't have to write `--input=src` in our terminal every time! input: 'src', } } }
Ahora, mejoremos nuestro blog-post.md
con nuestro nuevo shortcode. Pegue este contenido en nuestro archivo de rebajas:
# Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react '/components/TimesWeMispronouncedVite.jsx' %}
Y si ejecuta un npx eleventy
rápido, debería ver este resultado en su directorio _site
en /blog-post/index.html
:
<h1>Super interesting programming tutorial</h1> <p>Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example!</p> <div>This is where we'll import /components/TimesWeMispronouncedVite.jsx</div>
Escribiendo nuestro código abreviado de componente
Ahora hagamos algo útil con ese shortcode. ¿Recuerdas esa etiqueta de script
que escribimos mientras probamos Vite? Bueno, ¡podemos hacer lo mismo en nuestro shortcode! Esta vez usaremos el argumento componentPath
para generar la importación, pero mantendremos el resto más o menos igual:
// .eleventy.js module.exports = function(eleventyConfig) { let idCounter = 0; // copy all our /components to the output directory // so Vite can find them. Very important step! eleventyConfig.addPassthroughCopy('components') eleventyConfig.addShortcode('react', function (componentPath) { // we'll use idCounter to generate unique IDs for each "root" div // this lets us use multiple components / shortcodes on the same page idCounter += 1; const componentRootId = `component-root-${idCounter}` return ` <div></div> <script type="module"> // use JSON.stringify to // 1) wrap our componentPath in quotes // 2) strip any invalid characters. Probably a non-issue, but good to be cautious! import Component from ${JSON.stringify(componentPath)}; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('${componentRootId}'); ReactDOM.render(React.createElement(Component), componentRoot); </script> ` }) eleventyConfig.on('beforeBuild', function () { // reset the counter for each new build // otherwise, it'll count up higher and higher on every live reload idCounter = 0; }) return { dir: { input: 'src', } } }
Ahora, una llamada a nuestro shortcode (p. ej., {% react '/components/TimesWeMispronouncedVite.jsx' %}
) debería generar algo como esto:
<div></div> <script type="module"> import Component from './components/FancyLiveDemo.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('component-root-1'); ReactDOM.render(React.createElement(Component), componentRoot); </script>
Al visitar nuestro servidor de desarrollo usando (npx eleventy --watch) & vite _site
, deberíamos encontrar un hermoso elemento de contador en el que se puede hacer clic.
Alerta de palabra de moda: hidratación parcial y arquitectura de islas
Acabamos de demostrar la "arquitectura de las islas" en su forma más simple. Esta es la idea de que nuestros árboles de componentes interactivos no tienen que consumir todo el sitio web. En su lugar, podemos hacer girar mini-árboles, o "islas", en toda nuestra aplicación dependiendo de dónde realmente necesitemos esa interactividad. ¿Tienes una landing page básica de enlaces sin ningún estado que gestionar? ¡Genial! No hay necesidad de componentes interactivos. Pero, ¿tiene un formulario de varios pasos que podría beneficiarse de la biblioteca X React? No hay problema. Use técnicas como ese código abreviado de react
para activar una isla Form.jsx
.
Esto va de la mano con la idea de “hidratación parcial”. Es probable que haya escuchado el término "hidratación" si trabaja con SSG de componentes como NextJS o Gatsby. En resumen, es una manera de:
- Renderice primero sus componentes en HTML estático.
Esto le da al usuario algo que ver cuando visita inicialmente su sitio web. - “Hidrata” este HTML con interactividad.
Aquí es donde conectamos nuestros ganchos de estado y renderizadores para, bueno, hacer que los clics en los botones activen algo.
Este golpe 1-2 hace que los marcos impulsados por JS sean viables para sitios estáticos. Siempre que el usuario tenga algo que ver antes de que su JavaScript termine de analizarse, obtendrá una puntuación decente en esas métricas de referencia.
Bueno, hasta que no lo hagas. Puede ser costoso "hidratar" un sitio web completo, ya que necesitará un paquete de JavaScript listo para procesar hasta el último elemento DOM . ¡Pero nuestra técnica de código abreviado rudimentario no cubre toda la página! En su lugar, hidratamos "parcialmente" el contenido que está allí, insertando componentes solo donde es necesario.
No te preocupes, hay un complemento para todo esto: Slinkity
Recapitulemos lo que descubrimos aquí:
- Vite es un paquete increíblemente capaz que puede procesar la mayoría de los tipos de archivos (
jsx
,vue
ysvelte
, por nombrar algunos) sin configuración adicional. - Los códigos abreviados son una manera fácil de insertar fragmentos de HTML en nuestras plantillas, al estilo de los componentes.
- Podemos usar códigos abreviados para renderizar paquetes JS dinámicos e interactivos donde queramos usando hidratación parcial.
Entonces, ¿qué pasa con las compilaciones de producción optimizadas? ¿Está cargando correctamente los estilos con alcance? Diablos, ¿usar .jsx
para crear páginas completas? Bueno, he incluido todo esto (¡y mucho más!) en un proyecto llamado Slinkity. Estoy emocionado de ver la cálida recepción de la comunidad al proyecto, y me encantaría que usted, querido lector, le diera una oportunidad.
Pruebe la guía de inicio rápido
Astro también es genial
Los lectores con los ojos puestos en la tecnología de punta probablemente ya pensaron en Astro al menos una vez. ¡Y no puedo culparte! Está construido con un objetivo bastante similar en mente: comience con HTML simple e inserte componentes con estado donde los necesite. ¡Diablos, incluso te permitirán comenzar a escribir componentes React dentro de componentes Vue o Svelte dentro de archivos de plantilla HTML! Es como la edición MDX Xtreme.
Sin embargo, su enfoque tiene un costo bastante importante: debe reescribir su aplicación desde cero. Esto significa un nuevo formato de plantilla basado en JSX (con el que es posible que no se sienta cómodo), una canalización de datos completamente nueva a la que le faltan un par de sutilezas en este momento y errores generales a medida que resuelven los problemas.
¿Pero preparar un cóctel 11ty + Vite con una herramienta como Slinkity? Bueno, si ya tiene un sitio de 11ty, Vite debería encajar en su lugar sin tener que volver a escribir, y los códigos abreviados deberían cubrir muchos de los mismos casos de uso que los archivos .astro
. Admito que está lejos de ser perfecto en este momento. Pero bueno, ha sido útil hasta ahora, y creo que es una alternativa bastante sólida si desea evitar reescrituras en todo el sitio.
Terminando
Este experimento de Slinkity ha satisfecho mis necesidades bastante bien hasta ahora (¡y algunas de ustedes también!). Siéntase libre de usar cualquier pila que funcione para su JAM. Estoy emocionado de compartir los resultados de mi año de libertinaje de herramientas de compilación, y estoy muy emocionado de ver cómo podemos cerrar la gran brecha de Jamstack.
Otras lecturas
¿Quiere profundizar en la hidratación parcial, ESM o SSG en general? Mira estos:
- Arquitectura de las Islas
Esta publicación de blog de Jason Format realmente inició una discusión sobre "islas" e "hidratación parcial" en el desarrollo web. Está repleto de diagramas útiles y la filosofía detrás de la idea. - Simplifique su estática con un generador de sitio estático hecho a medida
Otro artículo de SmashingMag que lo guía a través de la creación de creadores de sitios web basados en Node desde cero. ¡Fue una gran inspiración para mí! - Cómo ES Modules ha redefinido el desarrollo web
Una publicación personal sobre cómo los módulos ES han cambiado el juego de desarrollo web. Esto profundiza un poco más en el "antes y ahora" de la sintaxis de importación en la web. - Una introducción a los componentes web
Un excelente tutorial sobre qué son los componentes web, cómo funciona el shadow DOM y dónde resultan útiles los componentes web. ¡Usé esta guía para aplicar componentes personalizados a mi propio marco!