Skip to content

Macros

A collection of macros for JSX. They are need to manually enabled by set macros to true.

DirectiveVueVolar
defineComponent
defineModel
defineSlots
defineExpose
defineStyle

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,
    }),
  ],
}

defineComponent

  • Support await keyword.
  • Automatically collects used props to the defineComponent's props option.
tsx
import { , , ,  } from 'vue'

const  = (
  async (: {
    ?: string
    ?: string
    // ^ unused prop will be as a fallthrough attribute.
  }) => {
    await ()
    const  = ()
    return (
      <>
        < {...}>{.}</>
      </>
    )
  },
)

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 } },
)
  • The destructured props will be automatically restructured.
  • If the prop's default value ends with !, the prop will be inferred as required.
  • If a rest prop is defined, it will be converted to useAttrs(), and the inheritAttrs option will default to false.
tsx
import {  } from 'vue'

const  = (
  <,>({  =  as ,  = ''!, ... }) => {
    return (
      <>
        < {...}>{}</>
      </>
    )
  },
)

export default () => <<string> foo={1} ="bar" />
Type 'number' is not assignable to type 'string'.
Compiled Code
tsx
import { defineComponent } from 'vue'
import { createPropsDefaultProxy } from '/vue-macros/jsx-macros/with-defaults'
defineComponent(
  (_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

  • Doesn't support hyphenated model names.
  • Will be inferred as a required prop when the expression ends with !.
  • The modified model's value can be read synchronously, without needing to await nextTick(). Related issue
tsx
import {  } from 'vue'

function () {
  const  = <string>()!
  . = 'foo'
  return <>{.}</>
}

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

  • If using generics to define slots, all slots will be optional.
tsx
const  = <{
  : () => any
}>()

.?.()
//           ^ optional
  • Support default slots (Recommended).
tsx
function <const >() {
  const  = ({
    : (: { ?:  }) => <>title slot: {.}</>,
    : (: { : number }) => <>default slot: {.}</>,
  })

  return (
    <>
      <. />
      <. ={1} />
    </>
  )
}

export default () => (
  <<1>>
    <template v-slot={{  }}>{}</template>
    <template v-slot:={{  }}>{}</template>
  </>
)

defineExpose

Just like in Vue SFC.

tsx
import {  } from 'vue-jsx-vapor'

const  = <,>({  =  as  }) => {
  ({
    ,
  })
  return < />
}

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 },
): void
  • Support CSS-variable and JS-variable binding.
  • Support defining multiple style macros in a file.
  • Support CSS pre-processors: css, scss, sass, less, stylus, postcss.
ts
defineStyle.scss(`...`)
defineStyle.stylus(`...`)
// ...
  • Support scoped mode.
    • If defined at the top level of the file, the scoped option defaults to false.
    • If defined within a function, the scoped option defaults to true.
tsx
function ({  = 'red' }) {
  .(`
    .foo {
      color: ${};

      :deep(.bar) {
        color: blue;
      }
    }
  `)
  return < ="red" ="foo bar">foo</>
}

(`
  .bar {
    background: black;
  }
`)
  • Support css modules, if the macro is an assignment expression.
tsx
export default () => {
  const  = .(`
    .foo {
      color: blue;
      .bar {
        background: red;
      }
    }
  `)

  return < ={.} />
}