JSX Classic vs JSX Automatic

Para el código JSX:

const List = ({elements}) => {
	return <ul>
      {elements.map(element => <Element text={element}/>)}
    </ul>;
}
const Element = ({text}) => {
	return {text.id}: {text.name};
}

Obtenemos dos posibles transformaciones de JSX, la «Classic», que es la que usaba React antes de la versión 17, y la «Automatic» que es desde la v17 en adelante.

JSX Classic:

const List = ({ elements }) => {
  return React.createElement("ul", null, elements.map(element => React.createElement(Element, {
    text: element
  })));
};
const Element = ({ text }) => {
  return React.createElement("li", null, text.id, ": ", text.name);
};

JSX Automatic:

import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";

const List = ({ elements }) => {
  return _jsx("ul", {
    children: elements.map(element => _jsx(Element, {
      text: element
    }))
  });
};

const Element = ({ text }) => {
  return _jsxs("li", {
    children: [text.id, ": ", text.name]
  });
};

La principal diferencia es que React.createElement es una función muy versatil. A partir del parametro #2 en adelante son todos los hijos de un elemento. Pudiendo ser ninguno o muchos.

En la nueva version, con el proposito de optimizar el renderizado, si la etiqueta tiene 0 o 1 hijo se transpila a _jsx, si tiene 2 o mas se transpila a _jsxs

Esto hace tambien que no tengamos que importar React en las versiones modernas, ya que ya se incluye en la transpilación «react/jsx-runtime» automaticamente.

AST Explorer War

Siempre uso porque es el que más me gusta y conozco el projecto el ASTExplorer de fkling en astexplorer.net. Creo que es el primero de los AST Explorer porque es el más indexado en buscadores, aunque no he revisiado la fecha del primer commit en github

astexplorer.net

Parece que hay una «guerra» de ast explorers. No compiten por nada, pero es interesante ver como surgen en el ecosistema de free software.

Li Hau Tan tambien tiene el suyo propio, aunque no está muy mantenido, como pieza de código a revisar es muy interesante.

babel ast explorer - Li Hau Tan

Parece que sxzz tambien se ha puesto a desarrollar el suyo, y no está nada mal:

ast explorer - sxzz

Bytecodes de V8

Con node podemos convertir el código javascript a los bytecodes que V8 ejecutará.

node --print-bytecode index.js

Franziska Hinkelman lo explica muy bien aqui

Pero el código generado a raiz de una función es mucho, porque se instancian los objetos globales y mucha estructura interna que debe estár ahi para ejecutar el programa completo.

Para filtar el código de una sola funcion se puede añadir el parámetro –print-bytecode-filter=nombre-de-funcion

node --print-bytecode --print-bytecode-filter=func_name index.js

Extra info:

Node.js under the hood #8 – Understanding bytecodes

JavaScript Bytecode – v8 Ignition Instructions

Babel Types by example

BabelJS es una herramienta que siempre me ha interesado. Originalmente 6to5, transformaba Javascript «nuevo» en Javascript «antiguo». Esta era su funcion principal para que la tarea del desarrollador no fuese tan dura al tener que duplicar implementación y aun así soportar navegadores menos actualizados (todos sabemos de quien estamos hablando …).

BABEL

Desde eso ha llovido mucho. Hoy soporta Typescript, JSX y la casi por nadie utilizada sintaxis de Flow. Así como una millonada de plugins disponibles en npm hacen que desarrollar con tu sabor favorito de JS sea más fácil que nunca.

Para progamar un plugin de Babel la propia librería esta dividida en distintos paquetes para ayudar al desarrollo. Aunque para ello tienes que conocer bien la sintaxis de JS, así como las otras sintaxis que también soporta.

Una función es una pieza de código que puede ser llamada en otra parte invocandola con parentesis.

function foo() {
    // 
}

const bar = function () { /* ...*/ }

const biz = () => 24;

Pero no es lo mismo si esta función está declarada directamente, o asignada a una variable, o asignada a una variable y además es una arrow function.

El analizador sintactico (parser) de babel transforma el codigo a una estructura de árbol para transformarla más fácilmente. Este árbol es simplemente un objeto con otros objetos anidados. La estructura se puede visualizar muy bien en ASTExplorer, que es un proyectazo muy util para entender lo que pasa por detrás de la transpilación.

Y aquí llega la parte aun más interesante. El tipo de objeto creado para repesentar una función será una FunctionDeclaration, pero si la estamos asignando es un FunctionExpression. Y bueno para la arrow function es una ArrowFunctionExpression.

Porque sí, no son lo mismo, el programa no sería representado de una manera unívoca si no tuviesemos estos distintos tipos. Todos los tipos que existen en babel están documentados en babel-types, que es el paquete de la librería con funciones para crear y comprobar tipos. Así se facilita mucho el desarrollo de un plugin.

En la documentación oficial explican como se debe usar cada metodo para crear un tipo y que parametros necesita. También si tiene algun alias, si el tipo es de Flow, Typescript o JSX y eso está geniar pero … no es muy didactica.

Para hacer más facil la comprensión de a que se refiere el nombre de cada tipo he publicado una documentación extendida, babel-types-by-example, con uno o varios ejemplos del elemento resaltado en un ejemplo de código.

Documentación de un jsxAttribute en @babel/types by example

Cómo se puede ver, cada tipo es una unidad comprensible por el parser de babel.

Espero que el pequeño «highlight» en cada uno de los elementos sea de ayuda. Para mi, el hecho de encotrar cada uno de los tipos dentro del código está siendo una formación genial en el lenguaje. El proyecto y la documentación de los ejemplos es un trabajo todabía en progreso, pero ya va tomando forma.

No pretende ser una documentación alternativa, ya que el script para generarla se basa en la oficial. Actualmente en versión 7 y pronto en 8 que está en beta. Si el lector tiene feedback sobre el proyecto o quiere contribuir toda ayuda es bienvenida.