feat: introduce jsx-macros
Description
This PR provides five macros for functional component.
-
defineComponent-
Auto collects usage props to the props option.
defineComponent((props: { foo: string, bar: string // ^ Unused prop as a fallthrough attribute will be automatically added to the root element's attributes. }) => { return () => ( <div> <span>{props.foo}</span> </div> ) })Will be covert to
defineComponent((props) => { return () => ( <div> <span>{props.foo}</span> </div> ) }, { props: { foo: null } }) -
The destructuring-props will be auto restructure and collects to the props option.
-
The rest prop will be convert to
attrs, And theinheritAttrsoption will defaults tofalse. By the way you can define the attrs type.defineComponent(({ foo, ...attrs }: { foo: string, bar: string }) => { return () => ( <div> <span {...attrs}>{foo}</span> </div> ) })Will be covert to
defineComponent((_props) => { const attrs = useAttrs() return () => ( <div> <span {...attrs}>{_props.foo}</span> </div> ) }, { inheritAttrs: false, props: { foo: null } }) -
Support
awaitexpression andgetCurrentInstance()co-usage. -
Support return JSX.
-
If the prop's default-value ends with
!, The prop will be inferred as required.
Usage
defineComponent(<T,>({ foo = undefined as T, barRequired = ''! // ^ specified the prop as required for Volar plugin. }) => { const modelValue = defineModel({ validator: (value) => value === 'model', required: true }) return ( <div class={props.class}> {[foo, modelValue.value]} </div> ) })Will be convert to:
defineComponent(<T,>(_props) => { const _default_props = createPropsDefaultProxy(_props, { 'barRequired': '' }); const modelValue = useModel(_props, 'modelValue') return () => ( <div> {[_props.foo, modelValue.value]} </div> ) }, { props: { foo: null, barRequired: { required: true }, modelValue: { validator: (value) => value === 'model', required: true }, 'onUpdate:modelValue': null, } }) -
-
defineModel- Don't support hyphenated modelName.
- Modified model's value can be read synchronously, needn't
await nextTick().
Related issue: https://github.com/vuejs/core/issues/11080 - Will be inferred as required prop when the expression ends with
!.
Usage
function Comp(){ const modelValue = defineModel<string>()! return <div /> } // will be convert to function Comp(props: { modelValue: string, 'onUpdate:modelValue': (e: string) => any }){ const modelValue = useModel<string>(props, 'modelValue', { required: true }) return <div /> } -
defineExposejust like in vue-setup.- Also support
react&preact
Setup
// vue-macros.config.ts import { defineConfig } from 'unplugin-vue-macros' export default defineConfig({ jsxMacros: { lib: 'react' // Or 'preact' }, scriptSFC: true, })Usage
const Comp = () => { const [foo] = useState() defineExpose({ foo }) return <div>{foo}</div> } // will be convert to: const Comp = forwardRef((props, _ref)=>{ const [foo] = useState() useImperativeHandle(_ref, () => ({ foo }),['foo']) return <div>{foo}</div> } - Also support
-
defineSlots- If you use generic to define slots, all slots will be optional.
const slots = defineSlots<{ default: () => any }>() slots.default?.() // ^ optional- Support default slots (Recommended).
function Comp(){ const slots = defineSlots({ default: (props: {foo: number}) => <div>default slot: {props.foo}</div> title: (props: {foo: number}) => <div>title slot: {props.foo}</div> }) return ( <> <slots.default foo={1} /> <slots.title foo={1} /> </> ) } -
defineStyle-
Support defining multiple style macros in a file.
-
Supported css pre-processors:
css|scss|sass|less|stylus|postcss.// default pre-processor is `css`. defineStyle(` .foo { color: red; } `) // use `scss` pre-processor. defineStyle.scss(``) -
Support
css modules, If the macro is an assignment expression.const { foo, bar } = defineStyle.scss(` .foo { color: blue; .bar { background: red; } } `) -
Support scoped mode.
- If defined at the top level of the file, The scoped option is
false. - If defined within a function, The scoped option defaults to
true.
Usage
defineStyle(` .foo { color: red; } `) // The scoped option is false. function Comp(){ defineStyle(`` { scoped: false // default is true, you can manually set to false. }) } - If defined at the top level of the file, The scoped option is
-
Support CSS-variable and JS-variable binding.
const Comp = () => { const color = ref('red') defineStyle.scss(` .foo { color: ${color.value}; } `) return <div class="foo" /> }
-
Run & review this pull request in StackBlitz Codeflow.
The latest updates on your projects. Learn more about Vercel for Git ↗︎
| Name | Status | Preview | Updated (UTC) |
|---|---|---|---|
| vue-macros | ✅ Ready (Inspect) | Visit Preview | Mar 14, 2025 2:11am |
🦋 Changeset detected
Latest commit: 22e745cd62303bb043928e30afd2b287c78e9cc8
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 34 packages
| Name | Type |
|---|---|
| @vue-macros/jsx-macros | Minor |
| unplugin-vue-macros | Minor |
| @vue-macros/volar | Minor |
| @vue-macros/config | Patch |
| @vue-macros/common | Patch |
| @vue-macros/astro | Patch |
| @vue-macros/nuxt | Patch |
| @vue-macros/api | Patch |
| @vue-macros/better-define | Patch |
| @vue-macros/boolean-prop | Patch |
| @vue-macros/chain-call | Patch |
| @vue-macros/define-emit | Patch |
| @vue-macros/define-models | Patch |
| unplugin-vue-define-options | Patch |
| @vue-macros/define-prop | Patch |
| @vue-macros/define-props-refs | Patch |
| @vue-macros/define-props | Patch |
| @vue-macros/define-render | Patch |
| @vue-macros/define-slots | Patch |
| @vue-macros/define-stylex | Patch |
| @vue-macros/export-expose | Patch |
| @vue-macros/export-props | Patch |
| @vue-macros/export-render | Patch |
| @vue-macros/hoist-static | Patch |
| @vue-macros/jsx-directive | Patch |
| @vue-macros/named-template | Patch |
| @vue-macros/reactivity-transform | Patch |
| @vue-macros/script-lang | Patch |
| @vue-macros/setup-block | Patch |
| @vue-macros/setup-component | Patch |
| @vue-macros/setup-sfc | Patch |
| @vue-macros/short-bind | Patch |
| @vue-macros/short-emits | Patch |
| @vue-macros/short-vmodel | Patch |
Not sure what this means? Click here to learn what changesets are.
Click here if you're a maintainer who wants to add another changeset to this PR
@vue-macros/api
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/api@794
@vue-macros/astro
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/astro@794
@vue-macros/better-define
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/better-define@794
@vue-macros/boolean-prop
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/boolean-prop@794
@vue-macros/chain-call
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/chain-call@794
@vue-macros/config
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/config@794
@vue-macros/common
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/common@794
@vue-macros/define-emit
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/define-emit@794
@vue-macros/define-models
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/define-models@794
unplugin-vue-define-options
npm i https://pkg.pr.new/vue-macros/vue-macros/unplugin-vue-define-options@794
@vue-macros/define-prop
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/define-prop@794
@vue-macros/define-props
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/define-props@794
@vue-macros/define-props-refs
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/define-props-refs@794
@vue-macros/define-render
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/define-render@794
@vue-macros/define-slots
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/define-slots@794
@vue-macros/define-stylex
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/define-stylex@794
@vue-macros/devtools
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/devtools@794
@vue-macros/eslint-config
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/eslint-config@794
@vue-macros/export-expose
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/export-expose@794
@vue-macros/export-props
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/export-props@794
@vue-macros/export-render
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/export-render@794
@vue-macros/hoist-static
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/hoist-static@794
@vue-macros/jsx-directive
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/jsx-directive@794
@vue-macros/jsx-macros
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/jsx-macros@794
vue-macros
npm i https://pkg.pr.new/vue-macros/vue-macros@794
@vue-macros/named-template
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/named-template@794
@vue-macros/nuxt
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/nuxt@794
@vue-macros/reactivity-transform
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/reactivity-transform@794
@vue-macros/script-lang
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/script-lang@794
@vue-macros/setup-block
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/setup-block@794
@vue-macros/setup-component
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/setup-component@794
@vue-macros/setup-sfc
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/setup-sfc@794
@vue-macros/short-bind
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/short-bind@794
@vue-macros/short-emits
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/short-emits@794
@vue-macros/short-vmodel
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/short-vmodel@794
@vue-macros/test-utils
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/test-utils@794
@vue-macros/volar
npm i https://pkg.pr.new/vue-macros/vue-macros/@vue-macros/volar@794
commit: 0bbb422
I have merged #851 in advance. so that I can use pkg-pr-new. Please review #851 first.