Blog de ingeniería de web.dev n.o 1: Cómo creamos el sitio y usamos componentes web

Esta es la primera entrada del blog de ingeniería de web.dev. En los próximos meses, esperamos compartir estadísticas prácticas de nuestro trabajo, así que busca las publicaciones con la etiqueta del blog de Ingeniería. Aquí, hablaremos sobre el proceso de compilación de nuestro sitio estático y el (opcional) JavaScript detrás de nuestros componentes web.

web.dev proporciona contenido sobre la compilación de experiencias web modernas y te permite medir el rendimiento de tu sitio. Es posible que los usuarios expertos se hayan dado cuenta de que nuestra página de medición es solo una interfaz de Lighthouse, que también está disponible en las Herramientas para desarrolladores de Chrome. Acceder a web.dev te permite ejecutar auditorías de Lighthouse de forma periódica en tu sitio para ver cómo cambia su puntuación con el tiempo. Volveré a visitar la página de medición más adelante, ya que creemos que es bastante especial. 🎊

Introducción

En esencia, web.dev es un sitio estático que se genera a partir de una colección de archivos Markdown. Elegimos usar Eleventy porque es una herramienta pulida y extensible que facilita la conversión de Markdown a HTML.

También usamos paquetes de JavaScript modernos que solo entregamos a navegadores compatibles con type="module", lo que incluye async y await. También usamos con gusto funciones que son compatibles con navegadores de larga duración, pero no con una minoría de versiones anteriores. Como somos un sitio estático, no es necesario usar JavaScript para leer nuestro contenido.

Una vez que se complete el proceso de compilación, que implica generar HTML estático y agrupar nuestro JavaScript con Rollup, web.dev se puede alojar con un servidor estático simple para realizar pruebas. El sitio es casi completamente estático, pero tenemos algunas necesidades especiales que aún se benefician de un servidor Node.js personalizado. Estos incluyen redireccionamientos para dominios no válidos, así como código para analizar el idioma preferido de un usuario para una próxima función de internacionalización.

Generación estática

Cada página de web.dev está escrita en Markdown. Todas las páginas incluyen material preliminar, que describe los metadatos de cada publicación. Estos metadatos se transfieren al diseño de cada página, lo que crea encabezados, etiquetas, etcétera. Por ejemplo:

---
layout: post
title: What is network reliability and how do you measure it?
authors:
  - jeffposnick
date: 2018-11-05
description: |
  The modern web is enjoyed by a wide swath of people…
---

The modern web is enjoyed by a wide swath of [people](https://www.youtube.com/watch?v=dQw4w9WgXcQ), using a range of different devices and types of network connections.

Your creations can reach users all across the world...

Este material preliminar nos permite definir propiedades arbitrarias, como los autores, la fecha de publicación y las etiquetas. Eleventy expone convenientemente el material preliminar como datos en casi todos los complementos, plantillas y otros contextos en los que nos gustaría hacer algo inteligente. El objeto de datos también contiene lo que Eleventy describe como la cascada de datos: una variedad de datos extraídos de cada página individual, del diseño que usa la página y de los datos que se encuentran en la estructura de carpetas jerárquica.

Cada diseño único describe un tipo de contenido diferente y puede heredar de otros diseños. En web.dev, usamos esta función para enmarcar correctamente diferentes tipos de contenido (como publicaciones y codelabs) y, al mismo tiempo, compartir un diseño HTML de nivel superior.

Colecciones

Eleventy proporciona una forma programática de compilar colecciones arbitrarias de contenido. Esto nos permitió crear compatibilidad con la paginación y generar páginas virtuales (páginas que no tienen un archivo Markdown coincidente en el disco) para los autores de las publicaciones. Por ejemplo, construimos nuestras páginas de autores con una plantilla que contiene una expresión para su vínculo permanente (para que la plantilla se vuelva a renderizar para cada autor) y una colección de respaldo.

Esto genera, por ejemplo, una página simple que contiene todas las publicaciones de Addy.

Limitaciones

En este momento, no podemos conectarnos fácilmente al proceso de compilación de Eleventy porque es declarativo, en lugar de imperativo: describes lo que quieres, en lugar de cómo lo quieres. Es difícil ejecutar Eleventy como parte de una herramienta de compilación más grande, ya que solo se puede invocar a través de su interfaz de línea de comandos.

Creación de plantillas

web.dev usa el sistema de plantillas Nunjucks que desarrolló originalmente Mozilla. Nunjucks tiene las funciones típicas de creación de plantillas, como bucles y condicionales, pero también nos permite definir atajos de teclado que generan más HTML o invocan otra lógica.

Al igual que la mayoría de los equipos que crean sitios de contenido estático, comenzamos de a poco y agregamos códigos cortos con el tiempo, alrededor de 20 hasta el momento. La mayoría de ellos solo generan más código HTML (incluidos nuestros componentes web personalizados). Por ejemplo:

{% Aside %}
See how Asides work in the web.dev codebase
{% endAside %}

Se verá de la siguiente manera:

Sin embargo, en realidad, crea HTML que se ve de la siguiente manera:

<div class="aside color-state-info-text">
<p>See how Asides work in the web.dev codebase</p>
</div>

Si bien está fuera del alcance de esta publicación, web.dev también usa códigos cortos como un tipo de lenguaje de metaprogramación. Los códigos cortos aceptan argumentos, uno de los cuales es el contenido contenido. No es necesario que los códigos cortos muestren nada, por lo que se pueden usar para crear un estado o activar algún otro comportamiento. 🤔💭

Guion

Como se mencionó antes, debido a que web.dev es un sitio estático, se puede entregar y usar sin JavaScript y por navegadores más antiguos que no admiten type="module" ni nuestro otro código moderno. Esta es una parte muy importante de nuestro enfoque para que web.dev sea accesible para todos.

Sin embargo, nuestro código para navegadores modernos consta de dos partes principales:

  1. Código de arranque, que incluye código para el estado global, Analytics y el enrutamiento de SPA
  2. Código y CSS para componentes web que mejoran el sitio de forma progresiva

El código de inicio es bastante sencillo: web.dev puede cargar páginas nuevas como una aplicación de una sola página (SPA), por lo que instalamos un objeto de escucha global que detecta clics en elementos <a href="..."> locales. El modelo de SPA nos ayuda a mantener el estado global de la sesión actual del usuario, ya que, de lo contrario, cada carga de página nueva activaría llamadas a Firebase para acceder al estado de acceso de un usuario.

También especificamos un par de puntos de entrada diferentes en nuestro sitio según la URL que hayas visitado y cargamos el correcto con import() dinámico. Esto reduce la cantidad de bytes que necesitan nuestros usuarios antes de que el sitio se mejore con código.

Componentes web

Los componentes web son elementos personalizados que encapsulan la funcionalidad del entorno de ejecución proporcionada en JavaScript y se identifican con nombres personalizados, como <web-codelab>. El diseño se adapta bien a sitios en gran parte estáticos, como web.dev: tu navegador administra el ciclo de vida de un elemento a medida que se actualiza el HTML de un sitio y, además, informa correctamente a los elementos cuando se adjuntan o se quitan de la página. Y los navegadores obsoletos simplemente ignoran los componentes web por completo y renderizan lo que queda en el DOM.

Cada componente web es una clase con métodos, como connectedCallback(), disconnectedCallback() y attributeChangedCallback(). Los elementos personalizados de web.dev heredan principalmente de LitElement, que proporciona una base simple para componentes complejos.

Si bien web.dev usa componentes web en muchas páginas, en ninguna parte es más necesario que en la página Measure. Dos elementos proporcionan la mayor parte de la funcionalidad que ves en esta página:

<web-url-chooser-container></web-url-chooser-container>
<web-lighthouse-scores-container></web-lighthouse-scores-container>

Estos elementos crean otros elementos que proporcionan más funcionalidad. Es importante destacar que estos elementos son solo parte de nuestro código fuente de Markdown normal, y nuestro equipo de contenido puede agregar funciones extendidas a cualquier página, no solo al nodo de medición.

Nuestros componentes web suelen usar el modelo de componente de contenedor, popularizado por React, aunque este modelo ya está un poco desactualizado. Cada elemento -container se conecta a nuestro estado global (proporcionado por unistore) y, luego, renderiza un elemento visual, que a su vez continúa renderizando nodos DOM reales que tienen diseño o alguna otra funcionalidad integrada.

Un diagrama que muestra la relación entre el estado global y los elementos HTML que lo usan.
Estado global y un componente web

Nuestros componentes web más complejos existen para visualizar acciones y estados globales. Por ejemplo, web.dev te permite auditar tu sitio favorito y, luego, salir de la página de medición. Si vuelves, verás que la tarea aún está en curso.

Nuestros componentes simples mejoran el contenido que, de otro modo, sería estático o crean visualizaciones increíbles (por ejemplo, cada gráfico de líneas es su propio <web-sparkline-chart>), que no tiene relación con el estado global.

Conversemos

El equipo de ingeniería de web.dev (Rob, Ewa, Michael y Sam) pronto publicará más análisis técnicos detallados.

Esperamos que te haya servido conocer cómo trabajamos para tus propios proyectos. Escríbenos en Twitter si tienes preguntas o solicitudes de temas para este blog.