Ejemplos de JSX vainilla
¿Y si JSX devolviera elementos del DOM?
- La función
ClickMe crea un botón y muestra la cantidad de clics
- El texto se actualiza cada vez que se hace clic en el botón
export default function ClickMe() {
let i = 0;
const el = Click me as HTMLButtonElement;
el.onclick = (e) => {
el.textContent = `Clicked ${++i} times`;
};
return el;
}
Reutilización
- El componente
ClickMe puede usarse varias veces y mantener un estado distinto en cada instancia
import ClickMe from "./sample1.js";
export default () =>
;
Creación de un árbol DOM interactivo
- Se puede administrar una lista de tareas usando las clases
TodoInput y TodoList
- Se pueden agregar elementos y eliminarlos con un clic
function TodoInput(attrs: { add: (v: string) => void }) {
const input = as HTMLInputElement;
input.placeholder = 'Add todo item...';
input.onkeydown = (e) => {
if (e.key === 'Enter') {
attrs.add(input.value);
input.value = '';
}
};
return input;
}
class TodoList {
ul = as HTMLUListElement;
add(v: string) {
const item =
- {v}
as HTMLLIElement;
item.onclick = () => item.remove();
this.ul.append(item);
}
}
export default () => {
const list = new TodoList();
list.add('foo');
list.add('bar');
return
list.add(v)} />
{list.ul}
;
};
Procesamiento de grandes volúmenes de datos
- La función
FindNames procesa y filtra grandes volúmenes de datos para mostrar resultados
- Actualiza en tiempo real los elementos coincidentes según el valor de entrada
import { data } from "../fetch-dataset.js";
export default function FindNames() {
const status = as HTMLParagraphElement;
const results = as HTMLUListElement;
const input = as HTMLInputElement;
updateMatches();
function updateMatches() {
const matched = (data.entries().filter(([k]) => k.match(input.value)).toArray());
const matches = (Iterator.from(matched).map(match => ).take(30));
results.replaceChildren(...matches);
status.textContent = `${matched.length} / ${data.size}`;
}
return
{input}
{status}
{results}
;
}
function Item(attrs: { match: [string, number], regex: string }) {
const [name, count] = attrs.match;
const total = ({count});
return
-
{total}
;
}
function highlight(str: string, regex: string) {
if (!regex) return str;
const r = new RegExp(`(${regex})`, 'gi');
return str.replace(r, '$1');
}
Introducción a imlib
imlib es una librería desarrollada para immaculatalibrary.com
- Se usa para construir minigamemaker.com y el sitio web que estás leyendo ahora
- Fue desarrollada porque el estado existente no era suficiente, y es la forma preferida de crear apps
Resumen de GN⁺
- Este artículo explica cómo crear e interactuar directamente con elementos del DOM usando JSX
- Presenta una forma de procesar grandes volúmenes de datos de manera eficiente sin usar un DOM virtual
- La librería
imlib permite desarrollar apps de una manera simple e intuitiva
- Otros proyectos con funciones similares incluyen React, Vue.js, etc.
1 comentarios
Opiniones en Hacker News
Si se devuelven nodos DOM reales, prácticamente se anulan grandes ventajas de JSX y de bibliotecas no-JSX como Lit: una API de estilo modo inmediato y el modelo
UI=f(state)Hay que devolver una descripción del DOM, no el DOM real, para poder reevaluar la plantilla con el nuevo estado y actualizar eficientemente el DOM en el que se renderiza esa plantilla
Los ejemplos actualizan con APIs DOM imperativas como
input.onkeydown = ...othis.ul.append(item), y probablemente una de las principales ventajas del DOM virtual sea evitar ese tipo de código y recorrer los elementos desde la plantillaDicho eso, el problema del DOM virtual es que el cálculo de diferencias es lento, y se puede resolver con plantillas que separen las partes estáticas y dinámicas, como Lit
Más bien produce el efecto contrario: te hace pensar “puedo volver a renderizar una UI grande a voluntad y el DOM virtual se encargará”, mientras el rendimiento real es malo y la estructura de la app ya quedó tan fija que es difícil arreglarla sin reescribirla
Vi el mismo patrón en cuatro equipos y, como arquitecto, recomendé una estructura vanilla consciente del rendimiento basándome en los problemas que tendrían con React, pero no fue aceptado porque “hay muchas formas de evitarlos”
Al final, parece que en muchos casos hay que aprender sufriéndolo en carne propia
createElement, y las ventajas descritas vienen del framework y del runtimeDicho más brevemente: JSX es una sintaxis alternativa de llamada a funciones que tiene usos útiles
En una empresa anterior usamos JSX para fábricas de datos de prueba; parecía XML, pero en la etapa de creación de elementos podíamos tomar decisiones contextuales ajustadas a los datos finales mediante el patrón builder
No tenía relación con React ni con el DOM, y tampoco significaba que no pudiera expresarse de forma declarativa sin JSX
Personalmente prefiero actualizar el DOM de forma imperativa. Puedo controlar con muchísimo detalle qué ocurre y diseñarlo con una estructura muy eficiente
Puedo hacer que sea fácil agregar, cambiar, eliminar y corregir funciones de la app sin tener que pensar según la metodología rígida de alguien más
UI=f(state)—, pero esto se siente como una de las abstracciones con fugas más notables de toda la computaciónHay una razón por la que alrededor de React surgió todo un ecosistema sobre cómo evitar renderizados múltiples o refrescos innecesarios
Creé este proyecto porque durante los últimos 10 años me frustró el estado de los generadores de sitios estáticos
Como suelo crear principalmente sitios web estáticos, quería una herramienta simple e intuitiva, y JSX parecía encajar bien, pero me cansó la complejidad excesiva de los frameworks JSX como React
Así que hice un generador de sitios estáticos que renderiza JSX como strings, y extenderlo al lado del navegador para renderizar JSX como elementos DOM fue algo natural
En algunos casos, especialmente en layouts, también encaja bien con componentes compartidos. En general estoy satisfecho con el resultado, aunque algunas partes son bastante hacky y el soporte de IDE podría mejorar
Además, este enfoque también encaja bien con SEO. Era un problema que no sentía bien resuelto en otros frameworks JSX
En la documentación quizá convendría escribir “static site generator” completo en vez de “SSG”. He usado generadores de sitios estáticos y aun así no sabía qué era SSG; tuve que preguntarle a una IA
Venía de usar Vue y me sorprendió: lit-html hace muchas de las cosas que hacen las plantillas de Vue, incluida la conexión de eventos, usando solo plantillas simples de vanilla JS
Con la extensión de Lit para VSCode puedes tener resaltado de sintaxis y verificación de tipos completa incluso dentro de las plantillas
Lo conocí después de que Marc Grabanski tuiteara que usaba lit-html con vanillajs, no Lit, y al probarlo por mi cuenta funcionó muy bien. Parece bastante parecido a lo que estás intentando resolver ahora
Con el paquete de plantillas
lit-htmlpuedes hacer la mayor parte de lo que se describe en el capítulo de plantillas: https://lit.dev/docs/templates/overview/También se puede sin la abstracción de componentes de
lit-element: https://lit.dev/docs/libraries/standalone-templates/#renderi...Lo interesante de estos “qué pasaría si” es que los orígenes de JSX se pueden rastrear hasta XHP de Facebook, y XHP se inspiró explícitamente en el estándar temprano de JS E4X, que se veía y funcionaba de forma parecida a la biblioteca descrita aquí
[1] https://engineering.fb.com/2010/02/09/developer-tools/xhp-a-...
[2] https://en.m.wikipedia.org/wiki/ECMAScript_for_XML
Por eso JSX superó a E4X, y desde entonces no hubo propuestas serias para plantillas HTML dentro de JS
Aun así, parece que la idea general podría revivirse con un enfoque moderno: https://github.com/WICG/webcomponents/issues/1069
for(of)en vez defor eachLa razón por la que no obtuvimos
for (:)es todavía más absurda: podía chocar con anotaciones:typeque algunos miembros de TC39 creían que algún día entrarían mágicamente al lenguajeAlguna vez hice una biblioteca de UI basada en la idea de que las expresiones de plantilla JSX crearan nodos DOM reales
También eliminaba parte del boilerplate de manejadores de eventos imperativos vinculando objetos de modelo a propiedades. Como seguramente imaginarán, me parece una buena idea
https://github.com/tomtheisen/mutraction
Permitía escribir código del estilo de crear un modelo con
track({ clicks: 0 }), incrementarmodel.clicksal hacer clic y reflejar ese valor directamente en el DOMTambién vale la pena mencionar VanJS aquí: https://vanjs.org/
Otras bibliotecas JSX como Solid.JS también devuelven nodos DOM, y me gusta que esta idea esté ganando fuerza
Creo que mientras más cerca estemos de la plataforma que usamos, mejor. Las capas de abstracción a veces pueden ser útiles, pero en la práctica todavía no encontré la necesidad de ocultar la plataforma
Tal vez proyectos enormes como Facebook sí se beneficien, pero no he trabajado a esa escala
Los ejemplos están geniales, pero parece importante que no muestren props de componentes que puedan cambiar con el tiempo
Esa capacidad en sí misma no parece estar modelada. Si no hace falta, es una forma ingeniosa, pero no veo bien cómo escalaría a apps más complejas
La diferencia es solo que permite escribir de forma más concisa unas 10 líneas de código que crean y configuran elementos DOM de la manera habitual
De hecho, lo realmente interesante de este framework es casi todo lo demás: devolver JSX como strings del lado del generador de sitios estáticos, tomar directorios de código fuente sin procesar y manipular
string|Bufferen el momento de SSG, y un sistema de módulos propio, muy eficiente y rápido, construido sobrechokidaryswcLa parte de usar JSX como DOM es la más llamativa visualmente, pero en realidad se parece más a un truco de fiesta
Por ejemplo, el código fuente de vanillajsx.com es muy conciso, claro y breve. Lo escribí todo en un solo día sin dependencias salvo
imlib, y la demo de JSX-como-DOM es la parte menos innovadora: https://github.com/sdegutis/vanillajsx.com/tree/main/siteSi te gusta esta forma en que JSX devuelve elementos DOM concretos, Solid funciona exactamente así, y además le suma una capa de reactividad bien hecha
setTimeoutosetIntervalDicho eso, coincido en que estos proyectos suelen funcionar bien para casos de uso pequeños, pero se rompen rápido en escenarios del “mundo real”
No creo que la implementación sea tan difícil
Esto es muy parecido a Vanilla TSX: https://github.com/wisercoder/uibuilder
Aquí hay un ejemplo de app escrita con Vanilla TSX: https://github.com/wisercoder/eureka/tree/master/webapp/Clie...
Me recuerda a ActionScript 3, que tenía XML en el núcleo del lenguaje
Era un lenguaje divertido de usar, pero fracasó de forma célebre en convertirse en ES4. Al final nos tomó más de 10 años llegar a un punto similar con TypeScript y JSX
Se desactivó para páginas web en Firefox 17, seis meses antes del primer lanzamiento de React
Me pregunto si hay alguien más a quien el último ejemplo no le funcione en Firefox. En Edge sí funcionó, pero en Firefox falló
Uncaught (in promise) TypeError: Map.groupBy(...).entries().map is not a functionNo termino de entender por qué JSX resulta atractivo frente a escribir algo como esto:
h("div", {}, [ h("p", {}, "this is easy"), ...list.map((l) => h("li", {}, l)) ])Así se obtienen automáticamente loops, interpolación de variables, etc., sin tener que crear un compilador ni una sintaxis nueva. Me gustaría que alguien me lo explicara
Para ser justos, en JSX también se usan loops e interpolación normales tal cual.
{}acepta expresiones de JS vanillaSolo que se necesita una etapa de compilación que descomponga las etiquetas de elementos en llamadas a
createElementCada persona procesa la información de forma distinta, pero ese ejemplo tiene tanta puntuación que es muy difícil captarlo rápido
Si no descompongo mentalmente la sintaxis, no veo la estructura del DOM que se genera, y entender la estructura del DOM de un vistazo es mucho más importante que si hace falta o no un compilador
Como referencia, soy una persona neurodivergente, y espero que esta explicación ayude
Como es similar a lo que ves en las herramientas de desarrollo del navegador, es más fácil compararlo y depurarlo
Pero en apps complejas, cuando tienes cientos de componentes y empiezan a importarse unos a otros, escribirlos como etiquetas JSX se siente como una sintaxis simple y fácil de entender
Gran parte de la reacción contra React también viene de que es excesivo para cosas simples, y de hecho lo es
Pero cada persona crea apps con distinta complejidad y requisitos, así que no se puede simplificar diciendo que un lado es más atractivo que el otro. Son herramientas distintas para problemas distintos