<script setup>
In this chapter, we're not discussing the mapping of a specific API, but rather looking from a macro perspective: how Vue's <script setup> is compiled into a complete React component.
Prerequisites
To avoid lengthy examples, this article focuses on the overall compilation results and structural changes of <script setup>:
<script setup>itself is a compile-time macro and is not preserved at runtime;- Its internal top-level code will be extracted into the React component function body;
- Vue templates will ultimately be transformed into JSX
returnstatements.
JavaScript: <script setup> to React Component Function
- Vue code:
vue
<script setup>
const props = defineProps({
title: String,
count: Number,
});
const emit = defineEmits(['update']);
const handleClick = () => {
emit('update', props.count + 1);
};
</script>
<template>
<button @click="handleClick">{{ props.title }} - {{ props.count }}</button>
</template>- React code after VuReact compilation:
jsx
const Comp = memo((props) => {
const handleClick = useCallback(() => {
props.onUpdate?.(props.count + 1);
}, [props.onUpdate, props.count]);
return (
<button onClick={handleClick}>
{props.title} - {props.count}
</button>
);
});
export default Comp;This transformation shows the core compilation approach of <script setup>:
- Non-pure UI components are wrapped with
memofor performance optimization. definePropsis not a runtime call, but is compiled into the component'spropsparameter;emitcalls are compiled intoprops.onXxxevent callbacks;- Most of the code you write in
script setupdirectly becomes functions inside the component; - Static optimization of script code during compilation;
- Vue templates are compiled into JSX within
return (...).
TypeScript: Overall Compilation of <script setup> with Types
- Vue code:
vue
<script setup lang="ts">
const props = defineProps<{
title: string;
count: number;
}>();
const emit = defineEmits<{
(e: 'update', value: number): void;
}>();
const handleClick = () => {
emit('update', props.count + 1);
};
</script>
<template>
<button @click="handleClick">{{ props.title }} - {{ props.count }}</button>
</template>- React code after VuReact compilation:
tsx
type ICompProps = {
title: string;
count: number;
onUpdate?: (value: number) => void;
};
const Comp = memo((props: ICompProps) => {
const handleClick = useCallback(() => {
props.onUpdate?.(props.count + 1);
}, [props.onUpdate, props.count]);
return (
<button onClick={handleClick}>
{props.title} - {props.count}
</button>
);
});This demonstrates:
- Type information in
<script setup lang="ts">is preserved and converted into componentpropstypes; - The type parameters of
definePropsare ultimately used in Reactpropstype definitions; - Event types from
defineEmitsare mapped to callback types likeonUpdate.
In TypeScript environments, VuReact also supports compiling JavaScript runtime parameter syntax of defineProps and defineEmits into corresponding TS type information.
- Vue code:
ts
const props = defineProps({
title: String,
count: Number,
});
const emit = defineEmits(['update']);- React code after VuReact compilation:
tsx
type ICompProps = {
title: string;
count: number;
onUpdate?: () => any;
};