# vue2-jsx-runtime
**Repository Path**: mirrors_LancerComet/vue2-jsx-runtime
## Basic Information
- **Project Name**: vue2-jsx-runtime
- **Description**: JSX runtime for Vue 2.
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-06-16
- **Last Updated**: 2026-01-03
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Vue 2 JSX Runtime
[](https://badge.fury.io/js/@lancercomet%2Fvue2-jsx-runtime)

This package is designed for handling Vue 2 JSX.
## What's the different between this and the official solution?
The official solution is a set of Babel plugins which convert JSX to Vue render function, and this package is the [New JSX Transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) implement for Vue 2. They are just two different ways to achieve the goal.
For TypeScript users, when you use the official solution your workflow would be like:
```
TSX -> Babel -> Vite (ESBuild) / TSC / SWC -> JS
```
The Babel just slows down the whole process, and we all know that these compilers actually support JSX transforming out of box. So if we have a Vue 2 New JSX Transform runtime for those compilers, we can just get rid of Babel.
For JavaScript users, you have to use Babel with it to transform JSX into JavaScript codes. [This example](https://github.com/LancerComet/vue2-jsx-runtime-webpack) shows how to use it with Babel and Webpack.
The reasons I developed this package:
1. I want to use Vite (it's fast) without ESBuild (doesn't support EmitDecoratorMetadata), so I have to use SWC + Vite, and I also need Vue 2 JSX support, but I don't want to bring Babel in.
3. Using `v-model` in `JSX-returing-setup()` with the official solution will break the Vue 2 app. It has been a long time but still not being fixed yet.
## Setup
First, please make sure `Vue@2` has been installed in your project, then
```
npm install @lancercomet/vue2-jsx-runtime --save
```
### Using TSC
Update your `tsconfig.json` with:
```js
{
"compilerOptions": {
...
"jsx": "react-jsx", // Please set to "react-jsx".
"jsxImportSource": "@lancercomet/vue2-jsx-runtime" // Please set to package name.
}
}
```
> The reason why "jsx" should be set to "react-jsx" is this plugin has to meet the new JSX transform.
### Using SWC
In `tsconfig.json`:
```js
{
"compilerOptions": {
...
"jsx": "preserve" // Please set to "preserve".
}
}
```
And in `.swcrc`:
```js
{
"jsc": {
"transform": {
"react": {
"runtime": "automatic", // Please set to "automatic" to enable new JSX transform.
"importSource": "@lancercomet/vue2-jsx-runtime", // Please set to package name.
"throwIfNamespace": false
}
}
}
}
```
### For JavaScript users
You can use it with [@babel/plugin-transform-react-jsx](https://babeljs.io/docs/en/babel-plugin-transform-react-jsx). You can [check this out](https://github.com/LancerComet/vue2-jsx-runtime-webpack) to see how to use it with Babel and Webpack.
### For Vite
Please read the section below.
## Usage
### Passing Value
#### Setup
```tsx
defineComponent({
setup () {
const isDisabledRef = ref(false)
return () => (
)
}
})
```
#### Render function
```tsx
Vue.extend({
data () {
return {
isDisabled: false
}
},
render () {
return (
)
}
})
```
### On
#### Setup
```tsx
setup () {
const onClick = () => {}
return () => (
)
}
```
#### Render function
```tsx
Vue.extend({
methods: {
onClick () {}
},
render () {
return
}
})
```
#### Using "on" object to assign multiple events for once
```tsx
```
### Native on
```tsx
```
Native is only available for Vue components.
### Rendering HTML or text
```tsx
// Setting HTML.
// Using Vue directive.
// Using dom prop.
// Setting text.
// Using Vue directive.
// Using dom prop.
```
### HTML / Component ref
#### Vue ≤ 2.6
Due to the limitation, using ref is a little different from to Vue 3.
You can check [this](https://github.com/vuejs/composition-api#limitations) out for more information.
```tsx
import { ComponentPublicInstance, defineComponent, onMounted } from '@vue/composition-api'
const Example = defineComponent({
setup () {
return () => (
Example goes here
)
}
})
const Wrapper = defineComponent({
setup (_, { refs }) {
onMounted(() => {
const div = refs.doge as HTMLElement
const example = refs.example as ComponentPublicInstance
})
return () => (
Wow very doge
)
}
})
```
#### Vue 2.7+
Vue 2.7 has its built-in composition API support, and the behavior acts as the same as Vue 3.
```tsx
import { ref, defineComponent } from 'vue'
const Example = defineComponent({
setup () {
const dogeRef = ref()
onMounted(() => {
console.log(dogeRef.value)
})
return () => (
)
}
})
// In render function.
const Example = Vue.extend({
data: () => ({
name: ''
}),
render: () =>
})
```
#### With modifiers
You can use modifiers to add some extra features:
- `lazy, number, trim`: These are the built-in modifiers from Vue.
- `direct`: See **"About IME"** section below.
```tsx
const Example = Vue.extend({
data: () => ({
name: '',
age: 0
}),
render: () => (
)
}
})
```
#### With argument
Argument of v-model is designed for binding properties.
Due to limitation, binding properties in Vue 2 isn't that kinda convenient:
```tsx
const userRef = ref({
detail: {
address: ''
}
})
// This works in Vue 3 but doesn't work in Vue 2.
```
We have to use v-model like:
```tsx
const Example = defineComponent({
setup () {
const userRef = ref({
username: '',
age: 0,
detail: {
address: ''
}
})
return () => (
)
}
})
```
#### About IME
By default, `v-model` will only assign what you have selected from IME. If you were typing in IME, `v-model` would do nothing.
If you want to disable this behavior, add `direct` modifier:
```tsx
{/* It will sync everything you have typed in IME. */}
{/* By default, it will only assign what you have selected from IME. */}
```
### Key
Due to the limitation, we have to use `v-bind:key`:
```tsx
{
userList.map(item => (
)
}
```
## Compatibility
These format below are also available, but they are NOT recommended, just for compatibility.
### On
```tsx
```
### v-model
```tsx
```
### Key
```tsx
```
## For Vite users
For Vite users, it's better to use TSC or SWC instead of built-in ESBuild. Because ESBuild is very finicky at handling JSX for now, and it gives you no room to change its behavior.
For faster compilation, SWC is recommended. You can use [unplugin-swc](https://github.com/egoist/unplugin-swc) to make Vite uses SWC.
Once you have switched to SWC (TSC) from ESBuild, you will not only be able to use JSX, but also get more features like `emitDecoratorMetadata` which is not supported by ESBuild, and the whole process is still darn fast.
### Configuration
After you have configured SWC (see Setup section above):
1. Install [unplugin-swc](https://github.com/egoist/unplugin-swc).
```
npm install unplugin-swc --save-dev
```
2. Update `vite.config.ts`:
```ts
import { defineConfig } from 'vite'
import swc from 'unplugin-swc'
import { createVuePlugin } from 'vite-plugin-vue2'
export default defineConfig({
plugins: [
swc.vite(),
createVuePlugin(),
...
]
})
```
## Mixing usage
If you have to use `JSX` and `SFC` together in Vite, you need to update your Vite config:
```ts
import { defineConfig } from 'vite'
import swc from 'unplugin-swc'
import { createVuePlugin } from 'vite-plugin-vue2'
const swcPlugin = swc.vite()
export default defineConfig({
plugins: [
{
...swcPlugin,
transform (code, id, ...args) {
if (
id.endsWith('.tsx') || id.endsWith('.ts') ||
(id.includes('.vue') && id.includes('lang.ts'))
) {
return swcPlugin.transform.call(this, code, id, ...args)
}
}
},
createVuePlugin(),
...
]
})
```
This will make SWC to skip compiling Non-Typescript codes in Vue SFC.
## Hot Reload
Use [vite-plugin-vue2-hmr](https://github.com/LancerComet/vite-plugin-vue2-hmr) to enable Vue2 JSX hot reload in Vite.
## Contributing
Feel free to open issue or pull request to make it better.
## References
- [Introducing the New JSX Transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html)
- [Render Function](https://vuejs.org/guide/extras/render-function.html)
- [vue-jsx-runtime (Vue 3)](https://github.com/dolymood/vue-jsx-runtime)
- [@vue/composition-api](https://github.com/vuejs/composition-api)
- [@vue/babel-plugin-jsx](https://github.com/vuejs/babel-plugin-jsx)