Macros
A collection of compile-time macros for JSX. These macros must be explicitly enabled by setting the macros option to true.
Setup
ts
import { defineConfig } from 'vite'
import vueJsxVapor from 'vue-jsx-vapor/vite'
export default defineConfig({
plugins: [
vueJsxVapor({
macros: true,
}),
],
})ts
import vueJsxVapor from 'vue-jsx-vapor/volar'
export default {
plugins: [
vueJsxVapor({
macros: true,
}),
],
}Install as a standalone plugin
A standalone plugin is also available for use in Virtual DOM projects.
bash
pnpm add @vue-jsx-vapor/macros -DConfiguration:
ts
// vite.config.ts
import jsxMacros from '@vue-jsx-vapor/macros/vite'
export default {
plugins: [
jsxMacros()
]
}defineComponent | defineVaporComponent
defineComponent is used to define Virtual DOM components, while defineVaporComponent is used to define Vapor components.
Options
ts
VueJsxVapor({
defineComponent: {
/**
* @default ['defineComponent','defineVaporComponent']
*
* Set alias to an empty array to disable the defineComponent macro.
*/
alias: []
}
})Features
- Supports the
awaitkeyword in async setup functions. - Automatically collects referenced props and adds them to the component's
propsoption.
tsx
import { , , , } from 'vue'
const = (
async (: {
?: string
?: string
// ^ Unreferenced props are treated as fallthrough attributes.
}) => {
await ()
const = ()
() => (
<>
< {...}>{.}</>
</>
)
},
)
export default () => (
<>
< ="foo" ="bar" />
</>
)Compiled Code
tsx
import { defineComponent, useAttrs, withAsyncContext } from 'vue'
defineComponent(
async (props) => {
let __temp, __restore
;([__temp, __restore] = withAsyncContext(() => nextTick())),
await __temp,
__restore()
const attrs = useAttrs()
return () => (
<div>
<span {...attrs}>{props.foo}</span>
</div>
)
},
{ props: { foo: null } },
)Props Handling
- Destructured props are automatically restructured to preserve reactivity.
- Append
!to a prop's default value to mark it as required. - Rest parameters in props are converted to
useAttrs(), andinheritAttrsdefaults tofalse.
tsx
import { } from 'vue'
const = (
<,>({ = as , = ''!, ... }) => {
(
<>
< {...}>{}</>
</>
)
},
)
export default () => <<string> foo={1} ="bar" />Compiled Code
tsx
import { defineVaporComponent } from 'vue'
import { createPropsDefaultProxy } from '/vue-macros/jsx-macros/with-defaults'
defineVaporComponent(
(_props) => {
const props = createPropsDefaultProxy(_props, { bar: '' })
const attrs = useAttrs()
return () => (
<div>
<span {...attrs}>{props.foo}</span>
</div>
)
},
{ props: { foo: null, bar: { required: true } }, inheritAttrs: false },
)defineModel
Limitations
- Hyphenated model names are not supported.
Features
- Append
!to mark the model as required. - Model values can be read synchronously after modification, without awaiting
nextTick(). Related issue
tsx
import { } from 'vue'
function () {
const = <string>()!
. = 'foo'
<>{.}</>
}
export default () => {
const = ('')
return < ={.} />
}Compiled Code
tsx
import { ref } from 'vue'
import { useModel } from '/vue-macros/jsx-macros/use-model'
function Comp(_props: {
modelValue: string
'onUpdate:modelValue': (value: string) => any
}) {
const modelValue = useModel<string>(_props, 'modelValue', { required: true })
modelValue.value = 'foo'
return <div>{modelValue.value}</div>
}defineSlots
Generic Slots
When using generics to define slots, all slots are treated as optional.
tsx
const = <{
: () => any
}>()
.?.()
// ^ optionalDefault Slot Values (Recommended)
Providing default implementations for slots is the recommended approach.
tsx
function <const >() {
const = ({
: (: { ?: }) => <>title slot: {.}</>,
: (: { : number }) => <>default slot: {.}</>,
})
(
<>
<. />
<. ={1} />
</>
)
}
export default () => (
<<1>>
<template v-slot={{ }}>{}</template>
<template v-slot:={{ }}>{}</template>
</>
)defineExpose
Functions identically to defineExpose in Vue SFCs.
tsx
import { } from 'vue-jsx-vapor'
const = <,>({ = as }) => {
({
,
})
< />
}
export default () => {
const = ()
.?.
return < ={} ={1 as } />
}Compiled Code
tsx
import { currentInstance } from 'vue'
import { useRef } from 'vue-jsx-vapor'
import { useExpose } from '/vue-macros/jsx-macros/use-expose'
const Comp = ({ foo }) => {
currentInstance.exposed = {
foo,
}
return <div />
}defineStyle
ts
declare function defineStyle(
style: string,
options?: { scoped?: boolean },
): voidFeatures
- Supports CSS variable and JavaScript variable binding.
- Multiple
defineStylecalls can be used within a single file. - Supports CSS preprocessors:
css,scss,sass,less,stylus,postcss.
ts
defineStyle.scss(`...`)
defineStyle.stylus(`...`)
// ...Scoped Styles
- Top-level definitions default to
scoped: false. - Definitions within functions default to
scoped: true.
tsx
function ({ = 'red' }) {
.(`
.foo {
color: ${};
:deep(.bar) {
color: blue;
}
}
`)
return < ="red" ="foo bar">foo</>
}
(`
.bar {
background: black;
}
`)CSS Modules
Assigning defineStyle to a variable enables CSS Modules support.
tsx
export default () => {
const = .(`
.foo {
color: blue;
.bar {
background: red;
}
}
`)
return < ={.} />
}