Construyendo un sitio estático con componentes usando Nunjucks
Publicado: 2022-03-10Es bastante popular en estos días, y me atrevo a decir que es una muy buena idea, construir sitios con componentes. En lugar de construir páginas enteras una por una, construimos un sistema de componentes (piense: un formulario de búsqueda, una tarjeta de artículo, un menú, un pie de página) y luego armamos el sitio con esos componentes.
Los marcos de JavaScript como React y Vue enfatizan mucho esta idea. Pero incluso si no usa ningún JavaScript del lado del cliente para crear un sitio, ¡no significa que tenga que renunciar a la idea de construir con componentes! Mediante el uso de un preprocesador HTML, podemos crear un sitio estático y seguir obteniendo todos los beneficios de abstraer nuestro sitio y su contenido en componentes reutilizables.
Los sitios estáticos están de moda en estos días, y con razón, ya que son rápidos, seguros y económicos de alojar. Incluso Smashing Magazine es un sitio estático, ¡lo creas o no!
Demos un paseo por un sitio que construí recientemente usando esta técnica. Utilicé CodePen Projects para construirlo, que ofrece Nunjucks como preprocesador, que estaba perfectamente preparado para el trabajo.
Un sitio de cuatro páginas con un encabezado, navegación y pie de página coherentes
Este es un micrositio. No necesita un CMS completo para manejar cientos de páginas. No necesita JavaScript para manejar la interactividad. Pero sí necesita un puñado de páginas que compartan el mismo diseño.
HTML por sí solo no tiene una buena solución para esto. Lo que necesitamos son importaciones . Lenguajes como PHP hacen esto simple con cosas como <?php include "header.php"; ?>
<?php include "header.php"; ?>
, pero los hosts de archivos estáticos no ejecutan PHP (a propósito) y HTML solo no es de ayuda. Afortunadamente, podemos preprocesar las inclusiones con Nunjucks.
Aquí tiene mucho sentido crear un diseño , incluidos fragmentos de HTML que representen el encabezado, la navegación y el pie de página. Las plantillas de Nunjucks tienen el concepto de bloques, que nos permiten ubicar el contenido en ese lugar cuando usamos el diseño.
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>The Power of Serverless</title> <link rel="stylesheet" href="/styles/style.processed.css"> </head> <body> {% include "./template-parts/_header.njk" %} {% include "./template-parts/_nav.njk" %} {% block content %} {% endblock %} {% include "./template-parts/_footer.njk" %} </body>
Observe que los archivos que se incluyen se denominan como _file.njk
. Eso no es del todo necesario. Podría ser header.html
o icons.svg
, pero se nombran así porque 1) los archivos que comienzan con guiones bajos son un poco una forma estándar de decir que son parciales. En CodePen Projects, significa que no intentarán compilarse solos. 2) Al nombrarlo .njk
, podríamos usar más cosas de Nunjucks allí si queremos.
Ninguno de estos bits tiene nada especial en ellos en absoluto. Son solo pequeños fragmentos de HTML destinados a ser utilizados en cada una de nuestras cuatro páginas.
<footer> <p>Just a no-surprises footer, people. Nothing to see here.<p> </footer>
Hecho de esta manera, podemos hacer un cambio y hacer que el cambio se refleje en las cuatro páginas.
Usando el diseño para las cuatro páginas
Ahora cada una de nuestras cuatro páginas puede ser un archivo. Sin embargo, comencemos con index.njk
, que en CodePen Projects se procesará automáticamente y creará un archivo index.html
cada vez que guarde.
Esto es lo que podríamos poner en index.njk
para usar el diseño y colocar algo de contenido en ese bloque:
{% extends "_layout.njk" %} {% block content %} <h1>Hello, World!</h1> {% endblock %}
¡Eso nos comprará una página de inicio completamente funcional! ¡Agradable! Cada una de las cuatro páginas puede hacer exactamente lo mismo, pero poniendo contenido diferente en el bloque, y tenemos un pequeño sitio de cuatro páginas que es fácil de administrar.
Para que conste, no estoy seguro de llamar a estos pequeños fragmentos componentes de reutilización. Solo estamos siendo eficientes y dividiendo un diseño en partes. Pienso en un componente más como un fragmento reutilizable que acepta datos y genera una versión única de sí mismo con esos datos. Llegaremos a eso.
Haciendo Navegación Activa
Ahora que hemos repetido un fragmento idéntico de HTML en cuatro páginas, ¿es posible aplicar CSS único a elementos de navegación individuales para identificar la página actual? Podríamos con JavaScript y mirando window.location
y demás, pero podemos hacerlo sin JavaScript. El truco es poner una class
en el <body>
única para cada página y usarla en el CSS.
En nuestro _layout.njk
, tenemos el cuerpo que genera un nombre de clase como variable:
<body class="{{ body_class }}">
Luego, antes de llamar a ese diseño en una página individual, establecemos esa variable:
{% set body_class = "home" %} {% extends "_layout.njk" %}
Digamos que nuestra navegación se estructuró como
<nav class="site-nav"> <ul> <li class="nav-home"> <a href="/"> Home </a> ...
Ahora podemos apuntar a ese enlace y aplicar un estilo especial según sea necesario al hacer:
body.home .nav-home a, body.services .nav-services a { /* continue matching classes for all pages... */ /* unique active state styling */ }
Ah, y esos iconos? Esos son solo archivos .svg
individuales que puse en una carpeta e incluí como
{% include "../icons/cloud.svg" %}
Y eso me permite diseñarlos como:
svg { fill: white; }
Suponiendo que los elementos SVG del interior no tengan atributos de fill
.
Creación de contenido en Markdown
La página de inicio de mi micrositio tiene una gran cantidad de contenido. Ciertamente podría escribir y mantener eso en HTML mismo, pero a veces es bueno dejar ese tipo de cosas a Markdown. Markdown se siente más limpio de escribir y quizás un poco más fácil de ver cuando hay muchas copias.
Esto es muy fácil en CodePen Projects. Creé un archivo que termina en .md
, que se procesará automáticamente en HTML, luego lo incluí en el archivo index.njk
.
{% block content %} <main class="centered-text-column"> {% include "content/about.html" %} </main> {% endblock %}
Construcción de componentes reales
Consideremos que los componentes son módulos repetibles que pasan datos para crearse a sí mismos. En marcos como Vue, estaría trabajando con componentes de un solo archivo que son fragmentos aislados de HTML con plantilla, CSS con ámbito y JavaScript específico del componente. Eso es genial, pero nuestro micrositio no necesita nada tan sofisticado.
Necesitamos crear algunas "tarjetas" basadas en una plantilla simple, para que podamos construir cosas como esta:
Construir un componente repetible como el de Nunjucks implica usar lo que ellos llaman Macros. Las macros son deliciosamente simples. ¡Son como si HTML tuviera funciones !
{% macro card(title, content) %} <div class="card"> <h2>{{ title }}</h2> <p>{{ content }}</p> </div> {% endmacro %}
Luego lo llamas según sea necesario:
{{ card('My Module', 'Lorem ipsum whatever.') }}
La idea general aquí es separar los datos y el marcado . Esto nos da algunos beneficios bastante claros y tangibles:
- Si necesitamos hacer un cambio en el HTML, podemos cambiarlo en la macro y se cambia en todas partes que usan esa macro.
- Los datos no están enredados en el marcado
- ¡Los datos podrían provenir de cualquier lugar! Codificamos los datos directamente en llamadas a las macros como lo hemos hecho anteriormente. O podríamos hacer referencia a algunos datos JSON y repetirlos. Estoy seguro de que incluso podría imaginar una configuración en la que los datos JSON provienen de una especie de CMS sin cabeza, proceso de compilación, función sin servidor, trabajo cron o lo que sea.
Ahora tenemos estas tarjetas repetibles que combinan datos y marcado, justo lo que necesitamos:
Haz tantos componentes como quieras
Puedes tomar esta idea y ejecutarla. Por ejemplo, imagine cómo Bootstrap es esencialmente un montón de CSS que sigue patrones HTML para usar. Puede hacer que cada uno de esos patrones sea una macro y llamarlos según sea necesario, esencialmente dividiendo el marco en componentes.
Puede anidar componentes si lo desea, adoptando una especie de filosofía de diseño atómico. Nunjucks también ofrece lógica, lo que significa que puede crear componentes condicionales y variaciones simplemente pasando diferentes datos.
En el sitio simple que hice, hice una macro diferente para la sección de ideas del sitio porque involucraba datos ligeramente diferentes y un diseño de tarjeta ligeramente diferente.
Un caso rápido contra los sitios estáticos
Podría argumentar que la mayoría de los sitios se benefician de una arquitectura basada en componentes, pero solo algunos sitios son apropiados por ser estáticos. Trabajo en muchos sitios en los que tener idiomas de back-end es apropiado y útil.
Uno de mis sitios, CSS-Tricks, tiene cosas como un inicio de sesión de usuario con un sistema de permisos algo complejo: foros, comentarios, comercio electrónico. Si bien ninguna de esas cosas detiene por completo la idea de trabajar de forma estática, a menudo me alegro de tener una base de datos y lenguajes de back-end para trabajar. Me ayuda a construir lo que necesito y mantiene las cosas bajo un mismo techo.
¡Avanza y abraza la vida estática!
Recuerde que uno de los beneficios de compilar de la forma en que lo hicimos en este artículo es que el resultado final es solo un montón de archivos estáticos. Fácil de alojar, rápido y seguro. Sin embargo, no teníamos que dejar de trabajar de una manera amigable para los desarrolladores. Este sitio será fácil de actualizar y agregar en el futuro.
- El proyecto final es un micrositio llamado The Power of Serverless for Front-End Developers (https://thepowerofserverless.info/).
- El alojamiento de archivos estáticos, si me preguntas, es parte del movimiento sin servidor.
- Puede ver todo el código (e incluso obtener una copia para usted) directamente en CodePen. Está construido, mantenido y alojado completamente en CodePen usando CodePen Projects.
- CodePen Projects maneja todas las cosas de Nunjucks de las que hablamos aquí, y también cosas como el procesamiento de Sass y el alojamiento de imágenes, que aproveché para el sitio. Puede replicar lo mismo con, por ejemplo, un proceso de compilación basado en Gulp o Grunt localmente. Aquí hay un proyecto repetitivo como ese que podrías hacer girar.