Transform JSX to function calls: <x />
-> h('x')
!
There is currently one project actively maintained that can transform JSX to function calls: Babel. Babel is amazing but ginormous (±300kb) and slow. Switching from it to estree in a project where Babel was only a small part made the whole project 68% smaller and 63% faster. So let’s make that two implementations.
This package is ESM only: Node 12+ is needed to use it and it must be import
ed
instead of require
d.
npm:
npm install estree-util-build-jsx
Say we have the following file, example.jsx
:
import x from 'xastscript'
console.log(
<album id={123}>
<name>Born in the U.S.A.</name>
<artist>Bruce Springsteen</artist>
<releasedate date="1984-04-06">April 6, 1984</releasedate>
</album>
)
console.log(
<>
{1 + 1}
<self-closing />
<x name key="value" key={expression} {...spread} />
</>
)
And our script, example.js
, looks as follows:
import fs from 'node:fs'
import {Parser} from 'acorn'
import jsx from 'acorn-jsx'
import {generate} from 'astring'
import {buildJsx} from 'estree-util-build-jsx'
const doc = fs.readFileSync('example.jsx')
const tree = Parser.extend(jsx()).parse(doc, {
sourceType: 'module',
ecmaVersion: 2020
})
buildJsx(tree, {pragma: 'x', pragmaFrag: 'null'})
console.log(generate(tree))
Now, running node example
yields:
import x from 'xastscript';
console.log(x("album", {
id: 123
}, x("name", null, "Born in the U.S.A."), x("artist", null, "Bruce Springsteen"), x("releasedate", {
date: "1984-04-06"
}, "April 6, 1984")));
console.log(x(null, null, 1 + 1, x("self-closing"), x("x", Object.assign({
name: true,
key: "value",
key: expression
}, spread))));
This package exports the following identifiers: buildJsx
.
There is no default export.
Turn JSX in tree
(Program
) into hyperscript calls.
Choose the runtime.
(string
, 'automatic'
or 'classic'
, default: 'classic'
).
Comment form: @jsxRuntime theRuntime
.
Place to import jsx
, jsxs
, and/or Fragment
from, when the effective
runtime is automatic (string
, default: 'react'
).
Comment: @jsxImportSource theSource
.
Note that /jsx-runtime
is appended to this provided source.
Add location info on where a component originated from (boolean
, default:
false
).
This helps debugging but adds a lot of code that you don’t want in production.
Only used when filePath
is and in the automatic runtime.
File path to the original source file (string
, example: 'path/to/file.js'
).
Used in the location info when using the automatic runtime with
development: true
.
Identifier or member expression to call when the effective runtime is classic
(string
, default: 'React.createElement'
).
Comment: @jsx identifier
.
Identifier or member expression to use as a sumbol for fragments when the
effective runtime is classic (string
, default: 'React.Fragment'
).
Comment: @jsxFrag identifier
.
Node
— The given tree
.
To support configuration from comments, those comments have to be in the
program.
This is done automatically by espree
.
For acorn
, it can be done like so:
import {Parser} from 'acorn'
import jsx from 'acorn-jsx'
var doc = ''
var comments = []
var tree = Parser.extend(jsx()).parse(doc, {onComment: comments})
tree.comments = comments
In almost all cases, this utility is the same as the Babel plugin, except that they work on slightly different syntax trees.
Some differences:
- No pure annotations or dev things
this
is not a component:<this>
->h('this')
, noth(this)
- Namespaces are supported:
<a:b c:d>
->h('a:b', {'c:d': true})
, which throws by default in Babel or can be turned on withthrowIfNamespace
- No
useSpread
,useBuiltIns
, orfilter
options
syntax-tree/hast-util-to-estree
— Transform hast (HTML) to estree JSXcoderaiser/estree-to-babel
— Transform estree to Babel trees