# 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 [![npm version](https://badge.fury.io/js/@lancercomet%2Fvue2-jsx-runtime.svg)](https://badge.fury.io/js/@lancercomet%2Fvue2-jsx-runtime) ![Testing](https://github.com/LancerComet/vue2-jsx-runtime/workflows/Test/badge.svg) 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 () => (
Wow very doge
) } }) ``` ### Slot ```tsx const Container = defineComponent({ setup (_, { slots }) { return () => (
{ slots.default?.() } { slots.slot1?.() } { slots.slot2?.() }
) } }) const Example = defineComponent({ name: 'Example', setup (_, { slots }) { return () => (
{ slots.default?.() }
) } }) ``` ```tsx Default Slot1 Slot2 ``` ### ScopedSlots ```tsx const MyComponent = defineComponent({ props: { name: String as PropType, age: Number as PropType }, setup (props, { slots }) { return () => (
{ slots.default?.() } { slots.nameSlot?.(props.name) } { slots.ageSlot?.(props.age) }
) } }) ``` ```tsx
Default
, nameSlot: (name: string) =>
Name: {name}
, ageSlot: (age: number) => { return
Age: {age}
} }} /> ``` Output: ```html
Default
Name: John Smith
Age: 100
``` ### Built-in directives #### Setup ```tsx defineComponent({ setup () { const isDisplayRef = ref(false) const textContentRef = ref('John Smith') const htmlContentRef = ref('

John Smith

') return () => (
Page content
) } }) ``` #### Render function ```tsx Vue.extend({ data () { return { isDisplay: false, textContent: 'John Smith', htmlContent: '

John Smith

' } }, render () { return (
Page content
) } }) ``` ### v-model #### Regular usage ```tsx import ref from '@vue/composition-api' import Vue from 'vue' // Setup. const Example = defineComponent({ setup () { const nameRef = ref('') 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: () => (
) }) const Example = defineComponent({ setup () { const nameRef = ref('') const ageRef = ref(0) return () => (
) } }) ``` #### 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 => (
{item.name}
)) }
``` ### Transition / TransitionGroup ```tsx import Vue from 'vue' const Transition = Vue.component('Transition') const TransitionGroup = Vue.component('TransitionGroup') setup () { return () => (
Some element
Some element
Some element
) } ``` or ```tsx setup () { return () => (
Some element
Some element
Some element
) } ``` ## 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)