As the title says
Why this ?
If you have used Vue's official jsx plugin, you will get how strange the syntax is, especially when you switch from React. You need to manually define props + defineComponent.setup and feel uncomfortable writing it.
import { ref, type VNode, defineComponent } from 'vue'
type Props = {
name: string
header: (count: number) => VNode
}
type Handler = {
addCount: () => void
}
const Child = defineComponent<Props>({
props: ['name', 'header'],
setup(props, ctx) {
const innerCount = ref(0)
ctx.expose<Handler>({
addCount() {
innerCount.value++
},
})
return () => (
<>
<div class="mb-2 border-b-[1px]">{props.header(innerCount.value)}</div>
<div class="cursor-pointer" onClick={() => innerCount.value++}>
{props.name} count: {innerCount.value}
</div>
{ctx.slots.default?.()}
</>
)
},
})This project is to solve the above verbose writing method and turn to React to use only one function to define jsx component writing method, example
Warning
THIS PLUGIN ONLY SUPPORT WITH Vue3 + Typescript + setup
npm i @mvcmlr/plugin-vue-jsx -Dvite.mts
import { defineConfig } from 'vite'
import vueJsx from '@mvcmlr/plugin-vue-jsx'
export default defineConfig({
plugins: [vueJsx()],
})tsconfig.json
import { effect, ref, type VNode } from 'vue'
type Props = {
name: string
header: (count: number) => VNode
children?: VNode
}
type Handler = {
addCount: () => void
}
function ChildComp(props: Props) {
const innerCount = ref(0)
defineExpose<Handler>({
addCount() {
innerCount.value++
},
})
return (
<>
<div class="mb-2 border-b-[1px]">{props.header(innerCount.value)}</div>
<div class="cursor-pointer" onClick={() => innerCount.value++}>
{props.name} count: {innerCount.value}
</div>
{props.children}
</>
)
}
function App() {
const count = ref(0)
const childCompRef = ref<Handler>()
effect(() => {
console.log('count change', count.value)
})
return (
<div>
<div class="cursor-pointer" onClick={() => count.value++}>
app count: {count.value}
</div>
<div
class="cursor-pointer"
onClick={() => childCompRef.value?.addCount()}
>
click to add count in child comp
</div>
<ChildComp
name="hello"
header={(count) => (
<>
<div>header </div>
<p>from ChildComp count :{count}</p>
</>
)}
ref={childCompRef}
>
<div>
<div>child app count: {count.value}</div>
</div>
</ChildComp>
</div>
)
}
export default App- Define jsx function
// ✔ return jsx element
const App = () => <div></div>
// ✔
function App() {
return <div></div>
}
// 🚫 without return jsx element
const App = () => '1111'
// 🚫 reference jsx variable
const Child = <div></div>
const App = () => Child- Nested jsx function
const App = () => {
const Child = (props: { a: number }) => {
// 🚫 🤔 Not support yet, maybe in the future
defineExpose({})
return <div>{props.a}</div>
}
// 🚫 🤔 Not support yet, maybe in the future
return <Child a={1} />
// ✔
return Child({ a: 1 })
}- Multiple return
const App = (props: { a: number }) => {
// ✔ use hook before return
const count1 = ref(0)
if (props.a == 1) return <div>1</div>
// 🚫 don't use hook after return
const count2 = ref(0)
if (props.a == 2) return <div>2</div>
return <div>3</div>
}Code based on:
- @vue/babel-plugin-resolve-type
- @vue/babel-plugin-jsx
- @vue/babel-helper-vue-transform-on
- @vitejs/plugin-vue-jsx
Inspired:
{ "compilerOptions": { // ... "jsx": "preserve", "jsxImportSource": "vue", }, }