Jsx-runtime for vue 3
vue-jsx-runtime
Vue 3 jsx runtime support.
The background https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html . With new jsx runtime support, which means a JSX ast standard, every lib can have its own jsx syntax with small limits.
Examples with TS:
TODO:
- optimize, transformOn, isCustomElement ...
- dev validation
- more tests
- more features
Installation
Install the plugin with:
pnpm add vue-jsx-runtime
# or
npm install vue-jsx-runtime
Usage
In Babel
// babel plugin
plugins: [
[
// add @babel/plugin-transform-react-jsx
'@babel/plugin-transform-react-jsx',
{
throwIfNamespace: false,
runtime: 'automatic',
importSource: 'vue-jsx-runtime'
}
],
],
In TypeScript
tsconfig.json
:
{
"compilerOptions": {
"jsx": "react-jsxdev", /* 'react-jsx' or 'react-jsxdev'. You can also use 'preserve' to use babel or other tools to handle jsx*/
"jsxImportSource": "vue-jsx-runtime"
}
}
If you used with Babel, you need to set the config:
{
"compilerOptions": {
"jsx": "preserve", /* 'react-jsx' or 'react-jsxdev'. You can also use 'preserve' to use babel or other tools to handle jsx*/
}
}
In Other Tools
If you use some tool which support jsx-runtime, like swc, you can use like this:
.swcrc
:
{
"jsc": {
"transform": {
"react": {
"runtime": "automatic",
"importSource": "vue-jsx-runtime"
}
}
}
}
More details, see https://swc.rs/docs/configuration/compilation#jsctransformreact
About esbuild, see https://github.com/evanw/esbuild/issues/1172 and a hack way https://github.com/evanw/esbuild/issues/832 . https://github.com/evanw/esbuild/issues/334#issuecomment-711444731 .
Syntax
Content
Functional component:
const App = () => <div>Vue 3.0</div>;
with render
const App = {
render() {
return <div>Vue 3.0</div>;
},
}
import { withModifiers, defineComponent } from "vue";
const App = defineComponent({
setup() {
const count = ref(0);
const inc = () => {
count.value++;
};
return () => (
<div onClick={withModifiers(inc, ["self"])}>{count.value}</div>
);
},
});
Fragment
const App = () => (
<>
<span>I'm</span>
<span>Fragment</span>
</>
);
Attributes / Props
const App = () => <input type="email" />;
with a dynamic binding:
const placeholderText = "email";
const App = () => <input type="email" placeholder={placeholderText} />;
Directives
v-show
const App = {
data() {
return { visible: true };
},
render() {
return <input v-show={this.visible} />;
},
};
v-model
A little different with @vue/babel-plugin-jsx
.
Syntax:
v-model={[object, ["path/key"], argument, ["modifier"]]}
Recommend:
const val = ref(1); // val.value will be 1
// jsx
<input v-model={val} /> // do not use v-model={val.value}
<input v-model:argument={val} />
v-model
will use val["value"]
to getter or setter by default.
Other usage
const val = ref(1);
<input v-model={[val, "value", ["modifier"]]} />
<A v-model={[val, "value", "argument", ["modifier"]]} />
Will compile to:
h(A, {
argument: val["value"],
argumentModifiers: {
modifier: true,
},
"onUpdate:argument": ($event) => (val["value"] = $event),
});
custom directive
Recommended when using string arguments
const App = {
directives: { custom: customDirective },
setup() {
return () => <a v-custom:arg={val} />;
},
};
const App = {
directives: { custom: customDirective },
setup() {
return () => <a v-custom={[val, ["value"], "arg", ["a", "b"]]} />;
},
};
Slot
Recommend
Use object slots:
const A = (props, { slots }) => (
<>
<h1>{ slots.default ? slots.default() : 'foo' }</h1>
<h2>{ slots.bar?.() }</h2>
</>
);
const App = {
setup() {
return () => (
<>
<A>
{{
default: () => <div>A</div>,
bar: () => <span>B</span>,
}}
</A>
<B>{() => "foo"}</B>
</>
);
},
};
Use v-slots
Note: In
jsx
,v-slot
should be replace withv-slots
const App = {
setup() {
const slots = {
bar: () => <span>B</span>,
};
return () => (
<A v-slots={slots}>
<div>A</div>
</A>
);
},
};
// or
const App = {
setup() {
const slots = {
default: () => <div>A</div>,
bar: () => <span>B</span>,
};
return () => <A v-slots={slots} />;
},
};
Different with vue jsx-next
jsx-next
is a plugin forBabel
only.vue-jsx-runtime
can be used withBabel
,TypeScript
,swc
,esbuild
and more.
vue-jsx-runtime
limits:
- can not merge ele/component props
v-model
syntax is little different withjsx-next
-v-model