VuReact 是一款Vue 转 React 编译工具,它能将 Vue 3 代码编译为标准、可维护的纯 React 。
🌐 Github:github.com/vureact-js/core
📃 官方文档:https://vureact.top
📢 写在前面
本教程帮助开发者在最短时间内上手 VuReact,并完成一个入门 Vue 3 项目到 React 项目的编译转换并启动应用。你将掌握从环境搭建、组件编写、编译配置到产物验证的全流程,无需深入了解 React 语法细节,即可利用现有 Vue 技能生成可运行的 React 工程。
完成后你会明确以下四件事:
- 输入 SFC 在什么约定下可稳定转换
- 编译后目录会长什么样
- 输出 TSX 与原始 SFC 的语义对应关系
- 编译器自动分析并追加 React hook 依赖,无需手动管理
🎥 推荐先观看下方的 2 分钟演示视频,快速建立对整个流程的直观印象。
VuReact 快速入门演示
开始:新建 Vite + Vue 工程
- 使用
Vite新建一个标准的Vue 3+TS项目:
npx create-vite@latest vue-app--templatevue-ts当出现交互式选择
Install with npm and start now?时,选择No。你将会看到类似以下工程目录结构(示意):
vue-app/ ├─ public/ ├─ src/ │ ├─ assets/ │ ├─ components/ │ │ └─ HelloWorld.vue │ ├─ App.vue │ ├─ main.ts │ └─ style.css ├─ index.html ├─ package.json ├─ tsconfig.json ├─ vite.config.ts └─ ...第1步:安装 VuReact
- 进入目录并安装项目依赖:
cdvue-appnpminstall- 安装 VuReact 编译核心:
npminstall-D@vureact/compiler-core第2步:配置 VuReact
在vue-app目录下新建vureact.config.ts:
// vue-app/vureact.config.tsimport{defineConfig}from'@vureact/compiler-core';exportdefaultdefineConfig({// 输入路径,包含要编译的 Vue 文件;允许输入单文件 'xxx.vue'input:'./src',// 排除 Vue 入口文件,避免语义冲突exclude:['src/main.ts'],output:{// 工作区目录,存放编译产物和缓存workspace:'.vureact',// 输出目录名outDir:'react-app',// 自动初始化 Vite React 环境bootstrapVite:true,},});除
exclude需手动指定外,其余选项均使用默认值,无需额外配置。
第3步:编写 Vue 组件
3.1 实现一个简单的计数器
将原来的HelloWorld.vue替换为计数器组件代码:
<!-- src/components/HelloWorld.vue --><template><sectionclass="counter-card"><h1>{{ props.title }}</h1><h2><spanclass="vureact">VuReact</span>➕<spanclass="vue">Vue</span>🟰<spanclass="react">React</span>({{ count }})</h2><p>{{ title }}</p><button@click="increment">+1</button><button@click="methods.decrease">-1</button></section></template><scriptsetuplang="ts">// @vr-name: HelloWorldimport{computed,ref,watch}from'vue';// 除了顶部的特殊注释外,也可以使用宏定义组件名// defineOptions({ name: 'HelloWorld' });// 必须使用 defineProps 定义 propsconstprops=defineProps<{title?:string}>();// 必须使用 defineEmits 定义 emitsconstemits=defineEmits<{(e:'update',value:number):void;}>();conststep=ref(1);constcount=ref(0);consttitle=computed(()=>`阶数:x${step.value}`);constincrement=()=>{count.value+=step.value;emits('update',count.value);};constmethods={decrease(){count.value-=step.value;emits('update',count.value);},};watch(count,(newVal)=>{step.value=Math.floor(newVal/10)||1;});</script><!-- VuReact 支持处理 Less 和 Sass --><stylescoped>.counter-card{border:1px solid #ddd;border-radius:8px;padding:12px;.vureact{color:#9932cc;}.vue{color:#42b883;}.react{color:#61dafb;}}</style>3.2 修改App.vue
<!-- src/App.vue --><scriptsetuplang="ts">// @vr-name: AppimportHelloWorldfrom'./components/HelloWorld.vue';</script><template><HelloWorldtitle="计数器组件"@update="(v) => {console.log(v)}"/></template>第4步:编译到 React 工程
方式一:使用 npx 命令
在vue-app目录下运行:
# 全量/增量编译npx vureact build# 或监听模式npx vureactwatch方式二:使用 npm scripts
在package.json里添加脚本命令:
"scripts":{"vr:build":"vureact build","vr:watch":"vureact watch"}npmrun vr:build运行命令后,终端会输出相关编译信息。
第5步:查看输出目录树
输出到vue-app/.vureact工作区目录(示意):
vue-app/ ├── .vureact/ # 工作区(编译生成) │ ├── cache/ # 编译缓存 │ ├── react-app/ # 生成的 Vite + React 工程 │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── HelloWorld.tsx │ │ │ │ └── HelloWorld-[hash].css │ │ │ ├── App.tsx │ │ │ ├── index.css │ │ │ ├── main.tsx │ │ │ └── style.css │ │ └── package.json │ │ └── tsconfig.json │ │ └── vite.config.ts │ │ └── ... │ │ ├── src/ # 原始 Vue 代码 ├── ... └── vureact.config.js # VuReact 配置文件第6步:运行 React 应用
- 进入
react-app目录:
cd.vureact/react-app- 安装依赖:
npmruninstall- 启动项目:
npmrun dev进入页面后,你可能会发现与 Vue 的页面样式存在差异,这是因为 Vite 初始化 React 后,自带的默认样式
index.css注入到了main.tsx中导致的,手动调整即可。
如遇问题,可查阅 常见问题 章节。
第7步:对照生成结果
下面是一个格式化后的典型输出(为说明做了轻微简化,实际哈希与属性名以本地产物为准):
import{useComputed,useVRef,useWatch}from'@vureact/runtime-core';import{memo,useCallback,useMemo}from'react';import'./HelloWorld-ebf8d8dc.css';// VuReact 根据 defineProps 和 defineEmits 自动生成exporttypeIHelloWorldProps={title?:string;}&{onUpdate?:(value:number)=>void;};// 自动使用 memo 优化组件constHelloWorld=memo((props:IHelloWorldProps)=>{// ref/computed 转换成了对等的适配 APIconststep=useVRef(1);constcount=useVRef(0);consttitle=useComputed(()=>`阶数:x${step.value}`);// 自动分析顶层箭头函数依赖,并追加 useCallback 优化constincrement=useCallback(()=>{count.value+=step.value;props.onUpdate?.(count.value);// emits 转换},[count.value,step.value,props.onUpdate]);// 自动分析顶层变量中的依赖,并追加 useMemo 优化constmethods=useMemo(()=>({decrease(){count.value-=step.value;props.onUpdate?.(count.value);},}),[count.value,step.value,props.onUpdate],);// watch 转成对等适配 APIuseWatch(count,(newVal)=>{step.value=Math.floor(newVal/10)||1;});return(<><section className="counter-card"data-css-ebf8d8dc><h1 data-css-ebf8d8dc>{props.title}</h1><h2 data-css-ebf8d8dc><spanclass="vureact"data-css-ebf8d8dc>VuReact</span>➕<spanclass="vue"data-css-ebf8d8dc>Vue</span>🟰<spanclass="react"data-css-ebf8d8dc>React</span>({count.value})</h2>{/* 自动补齐 ref .value 访问 */}<p data-css-ebf8d8dc>{title.value}</p><button onClick={increment}data-css-ebf8d8dc>+1</button><button onClick={methods.decrease}data-css-ebf8d8dc>-1</button></section></>);});// 自动保持组件导出exportdefaultCounter;CSS 文件内容:
.counter-card[data-css-ebf8d8dc]{border:1px solid #ddd;border-radius:8px;padding:12px;background:#fafafa;.vureact[data-css-ebf8d8dc]{color:#9932cc;}.vue[data-css-ebf8d8dc]{color:#42b883;}.react[data-css-ebf8d8dc]{color:#61dafb;}}关键观察点
// @vr-name: Counter这段特殊注释定义了组件名defineProps和defineEmits被转换成了 TS 组件类型- 非纯 UI 展示组件,默认会走
memo包装 ref/computed/watch被转换为 runtime 适配 API(useVRef/useComputed/useWatch)- 模板事件回调会生成符合 React 语义的
onClick - 顶层箭头函数自动分析依赖,尝试注入
useCallback - 顶层变量声明自动分析依赖,尝试注入
useMemo - 对 JSX 中的原
ref/computed状态值补上.value scoped样式会生成带哈希的 css 文件,并在元素上标注作用域属性
总结
通过以上步骤,你已完成了一个 Vue SFC 项目到 React 项目的完整编译流程。回顾整个过程:
- 初始化项目:使用 Vite 创建标准的 Vue + TS 工程
- 安装编译器:添加
@vureact/compiler-core依赖 - 编写配置:通过
vureact.config.ts指定输入、排除和输出规则 - 编写组件:按照约定(
@vr-name注释、defineProps/defineEmits宏)编写 SFC - 执行编译:使用 CLI 命令一键转换
- 运行产物:直接启动生成的 React 工程并验证效果
VuReact 在编译过程中拥有以下核心转换能力:
- Vue 模板语法 → React JSX(
v-if/v-slot/v-model/<slot>等) - Composition API → React Hooks(
ref→useVRef、computed→useComputed) - 响应式依赖分析 → 自动注入
useCallback/useMemo依赖数组 - 组件通信 → Props 类型推导 + 事件回调映射
- 样式处理 → Scoped CSS / CSS Modules / 预处理器一站式编译
常见问题
对于使用过程中的常见问题,可参考以下文档:
- ESLint 规则冲突
- FAQ
📚 推荐阅读
- 为什么运行时套壳注定失败?Vue 转 React 应走编译时路线(29号更新)
- Vue3转React实战:VuReact 可控混写迁移实战
- Vue转React终极指南:VuReact全特性语义对照
✨ 如果你觉得本文对你理解 VuReact 有帮助,欢迎点赞、收藏、关注!Github 仓库点亮 Star ⭐!