Vue 转 React | VuReact编译工具快速入门

VuReact 是一款 Vue 转 React 编译工具 ,它能将 Vue 3 代码编译为标准、可维护的纯 React 。

🌐 Github:github.com/vureact-js/core

📃 官方文档:https://vureact.top

📢 写在前面

本教程帮助开发者在最短时间内上手 VuReact,并完成一个入门 Vue 3 项目到 React 项目的编译转换并启动应用。你将掌握从环境搭建、组件编写、编译配置到产物验证的全流程,无需深入了解 React 语法细节,即可利用现有 Vue 技能生成可运行的 React 工程。

完成后你会明确以下四件事:

  1. 输入 SFC 在什么约定下可稳定转换
  2. 编译后目录会长什么样
  3. 输出 TSX 与原始 SFC 的语义对应关系
  4. 编译器自动分析并追加 React hook 依赖,无需手动管理

🎥 推荐先观看下方的 2 分钟演示视频,快速建立对整个流程的直观印象。

VuReact 快速入门演示

开始:新建 Vite + Vue 工程

  • 使用 Vite 新建一个标准的 Vue 3 + TS 项目:
bash 复制代码
npx create-vite@latest vue-app --template vue-ts
  • 当出现交互式选择 Install with npm and start now? 时,选择 No

  • 你将会看到类似以下工程目录结构(示意):

txt 复制代码
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

  • 进入目录并安装项目依赖:
bash 复制代码
cd vue-app
npm install
  • 安装 VuReact 编译核心:
bash 复制代码
npm install -D @vureact/compiler-core

第2步:配置 VuReact

vue-app 目录下新建 vureact.config.ts

ts 复制代码
// vue-app/vureact.config.ts
import { defineConfig } from '@vureact/compiler-core';

export default defineConfig({
  // 输入路径,包含要编译的 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 替换为计数器组件代码:

html 复制代码
<!-- src/components/HelloWorld.vue -->
<template>
  <section class="counter-card">
    <h1>{{ props.title }}</h1>
    <h2>
      <span class="vureact">VuReact</span>
      ➕
      <span class="vue">Vue</span>
      🟰
      <span class="react">React</span>
      ({{ count }})
    </h2>
    <p>{{ title }}</p>
    <button @click="increment">+1</button>
    <button @click="methods.decrease">-1</button>
  </section>
</template>

<script setup lang="ts">
// @vr-name: HelloWorld
import { computed, ref, watch } from 'vue';

// 除了顶部的特殊注释外,也可以使用宏定义组件名
// defineOptions({ name: 'HelloWorld' });

// 必须使用 defineProps 定义 props
const props = defineProps<{ title?: string }>();

// 必须使用 defineEmits 定义 emits
const emits = defineEmits<{
  (e: 'update', value: number): void;
}>();

const step = ref(1);
const count = ref(0);
const title = computed(() => `阶数:x${step.value}`);

const increment = () => {
  count.value += step.value;
  emits('update', count.value);
};

const methods = {
  decrease() {
    count.value -= step.value;
    emits('update', count.value);
  },
};

watch(count, (newVal) => {
  step.value = Math.floor(newVal / 10) || 1;
});
</script>

<!-- VuReact 支持处理 Less 和 Sass -->
<style scoped>
.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

html 复制代码
<!-- src/App.vue -->
<script setup lang="ts">
// @vr-name: App
import HelloWorld from './components/HelloWorld.vue';
</script>

<template>
  <HelloWorld
    title="计数器组件"
    @update="(v) => {console.log(v)}"
  />
</template>

第4步:编译到 React 工程

方式一:使用 npx 命令

vue-app 目录下运行:

bash 复制代码
# 全量/增量编译
npx vureact build

# 或监听模式
npx vureact watch

方式二:使用 npm scripts

package.json 里添加脚本命令:

json 复制代码
"scripts": {
  "vr:build": "vureact build",
  "vr:watch": "vureact watch"
}
bash 复制代码
npm run vr:build

运行命令后,终端会输出相关编译信息。

第5步:查看输出目录树

输出到 vue-app/.vureact 工作区目录(示意):

txt 复制代码
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 目录:
bash 复制代码
cd .vureact/react-app
  • 安装依赖:
bash 复制代码
npm run install
  • 启动项目:
bash 复制代码
npm run dev

进入页面后,你可能会发现与 Vue 的页面样式存在差异,这是因为 Vite 初始化 React 后,自带的默认样式 index.css 注入到了 main.tsx 中导致的,手动调整即可。

如遇问题,可查阅 常见问题 章节。

第7步:对照生成结果

下面是一个格式化后的典型输出(为说明做了轻微简化,实际哈希与属性名以本地产物为准):

ts 复制代码
import { useComputed, useVRef, useWatch } from '@vureact/runtime-core';
import { memo, useCallback, useMemo } from 'react';
import './HelloWorld-ebf8d8dc.css';

// VuReact 根据 defineProps 和 defineEmits 自动生成
export type IHelloWorldProps = {
  title?: string;
} & {
  onUpdate?: (value: number) => void;
};

// 自动使用 memo 优化组件
const HelloWorld = memo((props: IHelloWorldProps) => {
  // ref/computed 转换成了对等的适配 API
  const step = useVRef(1);
  const count = useVRef(0);
  const title = useComputed(() => `阶数:x${step.value}`);

  // 自动分析顶层箭头函数依赖,并追加 useCallback 优化
  const increment = useCallback(() => {
    count.value += step.value;
    props.onUpdate?.(count.value); // emits 转换
  }, [count.value, step.value, props.onUpdate]);

  // 自动分析顶层变量中的依赖,并追加 useMemo 优化
  const methods = useMemo(
    () => ({
      decrease() {
        count.value -= step.value;
        props.onUpdate?.(count.value);
      },
    }),
    [count.value, step.value, props.onUpdate],
  );
  
  // watch 转成对等适配 API
  useWatch(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>
          <span class="vureact" data-css-ebf8d8dc>VuReact</span>
          ➕
          <span class="vue" data-css-ebf8d8dc>Vue</span>
          🟰
          <span class="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>
    </>
  );
});

// 自动保持组件导出
export default Counter;

CSS 文件内容:

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;
  }
}

关键观察点

  1. // @vr-name: Counter 这段特殊注释定义了组件名
  2. definePropsdefineEmits 被转换成了 TS 组件类型
  3. 非纯 UI 展示组件,默认会走 memo 包装
  4. ref / computed/ watch 被转换为 runtime 适配 API(useVRef / useComputed/useWatch
  5. 模板事件回调会生成符合 React 语义的 onClick
  6. 顶层箭头函数自动分析依赖,尝试注入 useCallback
  7. 顶层变量声明自动分析依赖,尝试注入 useMemo
  8. 对 JSX 中的原 ref/computed 状态值补上 .value
  9. scoped 样式会生成带哈希的 css 文件,并在元素上标注作用域属性

总结

通过以上步骤,你已完成了一个 Vue SFC 项目到 React 项目的完整编译流程。回顾整个过程:

  1. 初始化项目:使用 Vite 创建标准的 Vue + TS 工程
  2. 安装编译器 :添加 @vureact/compiler-core 依赖
  3. 编写配置 :通过 vureact.config.ts 指定输入、排除和输出规则
  4. 编写组件 :按照约定(@vr-name 注释、defineProps/defineEmits 宏)编写 SFC
  5. 执行编译:使用 CLI 命令一键转换
  6. 运行产物:直接启动生成的 React 工程并验证效果

VuReact 在编译过程中拥有以下核心转换能力:

  • Vue 模板语法 → React JSX(v-if/v-slot/v-model/<slot> 等)
  • Composition API → React Hooks(refuseVRefcomputeduseComputed
  • 响应式依赖分析 → 自动注入 useCallback/useMemo 依赖数组
  • 组件通信 → Props 类型推导 + 事件回调映射
  • 样式处理 → Scoped CSS / CSS Modules / 预处理器一站式编译

常见问题

对于使用过程中的常见问题,可参考以下文档:

📚 推荐阅读


✨ 如果你觉得本文对你理解 VuReact 有帮助,欢迎点赞、收藏、关注!Github 仓库点亮 Star ⭐!

相关推荐
ppandss11 小时前
JavaWeb从0到1-DAY3.1- Vue(ii)
前端·javascript·vue.js
编码浪子1 小时前
Rust 1.95 稳定版解读与生态新动向
开发语言·后端·rust
qq_427539831 小时前
iframe 嵌入预览 PDF ,禁用右键菜单、打印下载按钮不展示
前端·javascript·vue.js·pdf
yu85939581 小时前
降低OFDM系统PAPR的各种算法及误码率分析
前端·算法
Rust研习社1 小时前
Rust 操作 Redis 从入门到生产级应用
开发语言·redis·后端·rust
2501_913061341 小时前
JVM虚拟机——面试中的八股文(下)
java·jvm·面试
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_3:(表单CSS美化实战与盒子模型三大核心属性详解)
前端·javascript·css·html
deviant-ART1 小时前
HttpServletResponse 中 Header 与 OutputStream 的正确使用顺序(避坑指南)
java·后端·servlet
编码者卢布1 小时前
【App Service】查看Application Insights自身SDK日志的方法示例
后端·python·flask