La nueva transformación JSX

Siguiendo con el post anterior de React 17, lo vuelvo a decir: No contiene nuevas funciones. No obstante, hay algo importante que han anunciado ayer 22 de septiembre el equipo de React:

React 17 brindará soporte para una nueva versión de la transformación JSX.

¿Qué es una transformación JSX?

Los navegadores como tal, no entienden JSX, por lo que la mayoría de los usuarios de React confían en algún compilador como Babel o TypeScript para transformar el código JSX en JavaScript normal. Muchos kit de herramientas preconfigurados como Create React App o Next.js también incluyen una transformación JSX por de bajo.

Junto con el lanzamiento de React 17, el equipo de react quiere hacer algunas mejoras en la transformación de JSX, pero no querían romper las configuraciones existentes. Es por eso que han trabajado junto con Babel para ofrecer una nueva versión reescrita de la transformación JSX para las personas que quisieran actualizar.

La actualización a la nueva transformación es completamente opcional, pero tiene algunos beneficios:

  • Con la nueva transformación, se puede usar JSX sin importar React.
  • Dependiendo de la configuración, la salida compilada puede mejorar ligeramente el tamaño del bundle.
  • Permitirá mejoras futuras que reduzcan la cantidad de conceptos que se necesita para aprender React.

Esta actualización no cambiará la sintaxis JSX y no es necesaria. La antigua transformación JSX seguirá funcionando como de costumbre y no hay planes para quitarle el soporte.

React 17 RC (Release Candidate) ya incluye soporte para la nueva transformación, así que ¡hay que probarlo!. Para que sea más fácil de adoptar, después del lanzamiento de React 17, también planean respaldar su soporte a React 16.x, React 15.x y React 0.14.x.

Veamos más de cerca las diferencias entre la transformación antigua y la nueva.

¿Qué es diferente en la nueva transformación?

Cuando se usa JSX, el compilador lo transforma en llamadas de función React que el navegador puede entender. La **antigua transformación JSX **convierte JSX en React.createElement(...).

Por ejemplo, digamos que el código se ve así:

import React from 'react'

function App() {
  return <h1>Hola Mundo</h1>
}

Por debajo, la antigua transformación JSX lo convierte en JavaScript normal:

import React from 'react'

function App() {
  return React.createElement('h1', null, 'Hola Mundo')
}

Sin embargo, esto no es perfecto:

  • Debido a que JSX se compiló en React.createElement, React debe estar dentro del alcance si se usa JSX.
  • Hay algunas mejoras de rendimiento y simplificaciones que React.createElement no permite.

Para resolver estos problemas, React 17 introduce dos nuevos puntos de entrada al paquete de React que están destinados a ser utilizados solo por compiladores como Babel y TypeScript. En lugar de transformar JSX en React.createElement, la nueva transformación JSX importa automáticamente funciones especiales de esos nuevos puntos de entrada en el paquete de React y las llama.

Digamos que nuestro código se ve así:

function App() {
  return <h1>Hola Mundo</h1>
}

Esto es lo que compila la nueva transformación JSX:

import { jsx as _jsx } from 'react/jsx-runtime'

function App() {
  return _jsx('h1', { children: 'Hola Mundo' })
}

Tengamos en cuenta, que en nuestro código original (JSX) ya no se necesita importar React para usar JSX. Pero aún se necesitaría importar React para usar Hooks u otras exportaciones que nos brinda React. De esto hablaré más abajo.

Este cambio es totalmente compatible con todo el código JSX que ya existe, por lo que no se tendrá que cambiar los componentes.


¿Cómo actualizar a la nueva transformación JSX?

Si no está preparado para actualizar a la nueva transformación JSX o si se está utilizando JSX para otra biblioteca, no hay que preocuparse. La transformación anterior no se eliminará y seguirá siendo compatible.

Si se desea actualizar, se necesitarán dos cosas:

  • Una versión de React que admita la nueva transformación (actualmente, solo React 17 RC lo admite, pero después de que se haya lanzado oficialmente React 17.0, el equipo de React planea hacer veesiones compatibles adicionales para 0.14.x, 15.x y 16.x).
  • Un compilador compatible.

Dado que la nueva transformación JSX no requiere que React esté dentro del alcance, también el equipo de React ha preparado un script automatizado que eliminará las importaciones innecesarias del código base.

Create React App

Se ha agregado compatibilidad con Create React App y estará disponible en la próxima versión v4.0, que actualmente se encuentra en beta.

Next.js

Next.js v9.5.3+ ya usa la nueva transformación para versiones de React compatibles.

Gatsby

Gatsby v2.24.5+ usa la nueva transformación para versiones compatibles

Configuración manual de Babel

El soporte para la nueva transformación JSX está disponible en Babel v7.9.0 y versiones superiores.

Primero, se deberá actualizar a la última transformación de Babel y sus complementos.

Si se está usando @babel/plugin-transform-react-jsx:

Para usuarios NPM

npm update @babel/core @babel/plugin-transform-react-jsx

Para usuarios Yarn

yarn upgrade @babel/core @babel/plugin-transform-react-jsx

Si se está usando @babel/preset-react:

Para usuarios NPM

npm update @babel/core @babel/preset-react

Para usuarios Yarn

yarn upgrade @babel/core @babel/preset-react

Actualmente, el antiguo transformador ("runtime": "classic") es la opción predeterminada. Para habilitar la nueva transformación, se puede pasar {"runtime": "automatic"} como una opción a @babel/plugin-transform-react-jsx o @babel/preset-react

// @babel/preset-react
{
  "presets": [
    [
      "@babel/preset-react",
      {
        "runtime": "automatic"
      }
    ]
  ]
}
// @babel/plugin-transform-react-jsx
{
  "presets": [
    [
      "@babel/plugin-transform-react-jsx",
      {
        "runtime": "automatic"
      }
    ]
  ]
}

A partir de Babel 8, "automatic" será el tiempo de ejecución predeterminado para ambos complementos.

Eslint

Si se está utilizando eslint-plugin-react, las reglas react/jsx-uses-react y react/react-in-jsx-scope ya no son necesarias y se pueden desactivar o eliminar (esto lo vimos en el post de standardjs).

{
  // ...
  "rules": {
    // ...
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off"
  }
}

TypeScript

TypeScript admite la transformación JSX en v4.1 beta.

Flow

Flow admite la nueva transformación JSX en v0.126.0 y posteriores.


Eliminación de importaciones React no utilizadas

Debido a que la nueva transformación JSX importará automáticamente las funciones react/jsx-runtime necesarias, React ya no necesitará estar dentro del alcance cuando se use JSX. Esto podría dar lugar a importaciones de React no utilizadas en el código. No está de más conversvarlas, pero si se desea eliminarlas, la recomendación es que ejecute un script para eliminarlas automáticamente.

cd nombre-proyecto
npx react-codemod update-react-imports

Al ejecutar este codificador:

  • Se eliminan todas las importaciones de React no utilizadas como resultado de la actualización a la nueva transformación JSX.
  • Se cambian todas las importaciones predeterminadas (es decir import React from 'react) a importaciones con nombre desestructuradas (ej: import { useState } from 'react), que el estilo preferido en el futuro. Este código no afectará las importaciones de espacios de nombres existentes (es decir import * as React from 'react), que también es un estilo válido. Las importaciones predeterminadas seguirán funcionando en React 17, pero a largo plazo, se recomienda alejarse de ellas.

Por ejemplo:

import React from 'react'

function App() {
  return <h1>Hola Mundo</h1>
}

Será reemplazado por:

function App() {
  return <h1>Hola Mundo</h1>
}

Si se usa alguna otra importación de React, por ejemplo, un Hook, entonces el codificador lo convertirá en una importación nombrada.

Por ejemplo:

import React from 'react'

function App() {
  const [text, setText] = React.useState('Hola Mundo')
  return <h1>{text}</h1>
}

Será reemplazado por:

import { useState } from 'react'

function App() {
  const [text, setText] = useState('Hola Mundo')
  return <h1>{text}</h1>
}

Además de limpiar las importaciones no utilizadas, esto también ayudará a prepararse para una futura principal versión de React (no 17, sino siguientes...) que admitirá módulos ES y no se tendrá que hacer una exportación predeterminada.

Bueno, este era más corto que el anterior.

Se vienen grandes cosas en React 17 ⚛️ 😱!!!

Fuente: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html (inglés)