JSX Introduction
JSX is a JavaScript syntax extension. Due to its good features and low learning cost, Gyron.js does not invent its own syntax but adapts existing JSX syntax sugar.
There are two JSX-related libraries in the core - they convert JSX syntax into runtime code, only difference is the runtime platform or plugin.
babel-plugin-jsx
babel-plugin-jsx is a Babel plugin that transforms JSX into Gyron.js method calls. Like other type libraries, it uses Babel's visitor API to convert JSXElement and other JSX tokens into executable h()
functions.
babel-plugin-jsx can also generate hot update
helper code in dev environments by using { hmr: true }
config. With this config, you can see __hmr_id
declared on component functions in source panel - a hash generated from file path and function name.
Then implement hot update logic in hot update APIs provided by different platforms. Currently only integrated with Vite, same process for other platforms.
Install
Install via package manager yarn
:
yarn add -D @gyron/babel-plugin-jsx
Usage
- Works with any Babel integration, e.g. in
babel-loader
for Webpack:
module.exports = {
module: {
rules: [
{
test: /\.(j|t)sx$/,
use: {
loader: 'babel-loader',
options: {
plugins: [
[
'@babel/plugin-transform-typescript',
{
isTSX: true,
},
],
[
'@gyron/babel-plugin-jsx',
{
setup: true,
},
],
],
},
},
},
],
},
}
- Or directly use
babelWebpack
exported by@gyron/babel-plugin-jsx
for transformation:
Default export babelWebpack
in config file:
module.exports = require('./index').babelWebpack
Then in Webpack:
module.exports = {
module: {
rules: [
{
test: /\.(j|t)sx$/,
use: [
{
loader: './gyron.config.js',
options: {
setup: true,
},
},
],
},
],
},
}
Can also use ESM syntax transform JSX in node > 14
:
import babelJsx from '@gyron/babel-plugin-jsx'
export default {
plugins: [babelJsx],
}
Options
babel-plugin-jsx accepts options to generate more suitable code:
hmr
- Generate hot update helper code.ssr
- Generate SSR hydrate helper code. Auto inject component props oncreateSSRContext
.setup
- Auto convert stateless to stateful components.
Hot Update
babel-plugin-jsx auto finds Gyron components and attaches runtime helper
code on component functions to support hot update. Just using it doesn't work, still need to know how to rerender
. Typically we identify comment
nodes in code and insert rerender helper
code to update. See vite-plugin-jsx
implementation for details.
Gyron auto finds component dependencies and updates them in dev environments.
import { FC } from 'gyron'
const App = FC(() => {
return <div>App</div>
})
// ↓ ↓ ↓ ↓ ↓
const App = FC(() => {
return h('div', null, ['App'])
})
App.__hmr_id = 'xxaanncc'
Plugins
We provide out-of-box plugins for the following platforms for easy integration:
Both plugins are in babel-plugin-jsx
package, exported differently. Both accept options to control transform.
-
esbuild
esbuild is an extremely fast bundler, 10-100x faster than alternatives.
import esbuild from 'esbuild'
import { babelESBuildJsx } from '@gyron/babel-plugin-jsx'
esbuild.build({
// ...
plugins: [
babelESBuildJsx({
hmr: true,
setup: true,
}),
],
})
-
vite
vite is next generation frontend tooling with lightning fast dev server.
import { defineConfig } from 'vite'
import { babelViteJsx } from '@gyron/babel-plugin-jsx'
export default () => {
return defineConfig({
plugins: [
babelViteJsx({
hmr: true,
setup: true,
}),
],
})
}
Transforms
To maintain intuitive coding habits, babel-plugin-jsx
generates some helper code that needs to be enabled via options, off by default. If unexpected errors occur, try disabling helpers and check.
Gyron components are stateful or stateless, only difference is function return value. Often stateless isn't needed but used for intuitive coding. The setup
option enables:
import { FC } from 'gyron'
const HelloWorld = FC<{ msg: string }>(({ msg }) => {
function onClick() {
if (msg === '') {
console.log('gyron.js')
}
}
return <div onClick={onClick}>{msg}</div>
})
// ↓ ↓ ↓ ↓ ↓
import { onBeforeUpdate as _onBeforeUpdate } from 'gyron'
import { FC } from 'gyron'
const HelloWorld = FC<{ msg: string }>(({ msg }) => {
// Auxiliary update of deconstructed props
_onBeforeUpdate((_, props) => {
var _props = props
msg = _props.msg
})
function onClick() {
if (msg === '') {
console.log('gyron.js')
}
}
return ({ msg }) => <div onClick={onClick}>{msg}</div>
})
jsx-runtime
jsx-runtime supports modern jsx factories, usually for babel-plugin-transform-react-jsx plugin.
Install via yarn
:
yarn add -D @gyron/jsx-runtime
Usage
Note pragma
config and related imports if specified.
/** @jsx h */
import { h } from '@gyron/jsx-runtime'
// Then JSX can be used
const App = () => {
return <div>Hello World</div>
}
A simple @gyron/jsx-runtime
+ Vite example:
Note Vite doesn't load jsx-runtime initially so first load shows blank page. Just refresh and it works. Or upgrade to Vite v3.
import { defineConfig } from 'vite'
export default ({ mode }) => {
return defineConfig({
esbuild: {
jsxInject: `import { h, Fragment } from '@gyron/jsx-runtime'`,
jsxFactory: 'h',
jsxFragment: 'Fragment',
},
})
}