Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
> It converts Vue 3 SFCs, scripts, and styles into pure React without a runtime bridge, with full
> `<script setup>` support and progressive migration.

[![Stars](https://img.shields.io/github/stars/vureact-js/core?style=flat-square&color=magenta)](https://github.com/vureact-js/core)
[![Stars](https://img.shields.io/github/stars/vureact-js/core?style=flat-square&color=magenta)](https://github.com/vureact-js/core/stargazers)
[![Npm](https://img.shields.io/npm/v/@vureact/compiler-core.svg?label=Npm&style=flat-square)](https://vureact.top/en/)
[![Downloads](https://img.shields.io/npm/dt/@vureact/compiler-core?label=Downloads&style=flat-square&color=red)](https://www.npmjs.com/package/@vureact/compiler-core)
[![Monthly](https://img.shields.io/npm/dm/@vureact/compiler-core?label=Monthly&style=flat-square)](https://www.npmjs.com/package/@vureact/compiler-core)
Expand Down
4 changes: 2 additions & 2 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

**Vue 書いて、メンテナブルな React を生成。**

> Vue→React 移行のためのコンパイラツールチェーン
> Vue→React 移行と混在開発のための完全なソリューション
>
> Vue 3 SFC・Script・Style をランタイムなしで純粋な React へ変換。`<script setup>` ・段階的移行・混在開発に対応。

[![Stars](https://img.shields.io/github/stars/vureact-js/core?style=flat-square&color=magenta)](https://github.com/vureact-js/core)
[![Stars](https://img.shields.io/github/stars/vureact-js/core?style=flat-square&color=magenta)](https://github.com/vureact-js/core/stargazers)
[![Npm](https://img.shields.io/npm/v/@vureact/compiler-core.svg?label=Npm&style=flat-square)](https://vureact.top/en/)
[![Downloads](https://img.shields.io/npm/dt/@vureact/compiler-core?label=Downloads&style=flat-square&color=red)](https://www.npmjs.com/package/@vureact/compiler-core)
[![Monthly](https://img.shields.io/npm/dm/@vureact/compiler-core?label=Monthly&style=flat-square)](https://www.npmjs.com/package/@vureact/compiler-core)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

**写 Vue,输出可维护的 React。**

> 一个面向 Vue 迁移/混合 React 的完整解决方案
> 一套面向 Vue 迁移 React 和混合开发的完整解决方案
>
> 将 Vue 3 SFCs・Scripts・Styles 完整转为纯 React(非运行时桥接),
> 覆盖 `<script setup>` 核心全特性,支持渐进式迁移与混合开发。

[![Stars](https://img.shields.io/github/stars/vureact-js/core?style=flat-square&color=magenta)](https://github.com/vureact-js/core)
[![Stars](https://img.shields.io/github/stars/vureact-js/core?style=flat-square&color=magenta)](https://github.com/vureact-js/core/stargazers)
[![Npm](https://img.shields.io/npm/v/@vureact/compiler-core.svg?label=Npm&style=flat-square)](https://vureact.top/)
[![Downloads](https://img.shields.io/npm/dt/@vureact/compiler-core?label=Downloads&style=flat-square&color=red)](https://www.npmjs.com/package/@vureact/compiler-core)
[![Monthly](https://img.shields.io/npm/dm/@vureact/compiler-core?label=Monthly&style=flat-square)](https://www.npmjs.com/package/@vureact/compiler-core)
Expand Down
1 change: 0 additions & 1 deletion packages/compiler-core/CHANGELOG-zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- 修复模板修饰符事件没有表达式时,模板解析直接崩溃 [#43](https://github.com/vureact-js/core/issues/43)
- 修复 `<slot>` 搭配 v-else 时,slot props 解析崩溃 [#44](https://github.com/vureact-js/core/issues/44)
- 修复 JSX children 构建对异常 children 形态缺乏容错 [#45](https://github.com/vureact-js/core/issues/45)
- 修复当 provide() 内部使用 computed() 会漏转为 React 产物 [#46](https://github.com/vureact-js/core/issues/46)
- 修复 Vue 类型的 import 在编译后被移除,但代码中对应类型引用未移除,导致 TS 类型错误 [#47](https://github.com/vureact-js/core/issues/47)
- 修复在依赖分析中(如 watchEffect),对代码中的混合了可选链的对象访问,未添加可选链保护导致崩溃的问题 [#48](https://github.com/vureact-js/core/issues/48)
- 修复编译器在处理模板特殊事件时,生成了错误的运行时方法 dir.On,导致页面奔溃的问题 [#49](https://github.com/vureact-js/core/issues/49)
Expand Down
1 change: 0 additions & 1 deletion packages/compiler-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed template parser crash when modifier events had no expression [#43](https://github.com/vureact-js/core/issues/43)
- Fixed `<slot>` with `v-else` causing slot props parsing crash [#44](https://github.com/vureact-js/core/issues/44)
- Fixed JSX children builder lacking tolerance for abnormal children shapes [#45](https://github.com/vureact-js/core/issues/45)
- Fixed `provide()` using `computed()` internally not being converted to React output [#46](https://github.com/vureact-js/core/issues/46)
- Fixed Vue type imports being removed after compilation but corresponding type references in code not being removed, causing TS type errors [#47](https://github.com/vureact-js/core/issues/47)
- Fixed dependency analysis (e.g., `watchEffect`) missing optional chaining protection for object access mixed with optional chaining, causing crashes [#48](https://github.com/vureact-js/core/issues/48)
- Fixed compiler generating incorrect runtime method `dir.On` when handling special template events, causing page crashes [#49](https://github.com/vureact-js/core/issues/49)
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

It is used to fully convert Vue 3 SFCs, Scripts, and Styles into pure React (non-runtime bridge) code and output engineered artifacts, covering all core features of `<script setup>`, and supporting progressive migration and hybrid development.

[![Stars](https://img.shields.io/github/stars/vureact-js/core?style=flat-square&color=magenta)](https://github.com/vureact-js/core/stargazers)
[![Downloads](https://img.shields.io/npm/dt/@vureact/compiler-core?label=Downloads&style=flat-square)](https://www.npmjs.com/package/@vureact/compiler-core)
[![Node](https://img.shields.io/badge/node-%3E%3D19.0.0-green?label=Node)](https://nodejs.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/vureact-js/core/blob/master/LICENSE)
Expand Down
4 changes: 2 additions & 2 deletions packages/compiler-core/README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# @vureact/compiler-core

`@vureact/compiler-core` 是一个面向 Vue 迁移 React / Vue + React 混合开发的完整解决方案。VuReact 的 **CLI 与核心编译包**。
`@vureact/compiler-core` 是一套面向 Vue 迁移 React 和混合开发的完整解决方案。VuReact 的 **CLI 与核心编译包**。
它用于将 Vue 3 SFCs・Scripts・Styles 完整转为纯 React(非运行时桥接)代码并输出工程化产物,覆盖 `<script setup>` 核心全特性,支持渐进式迁移和混合开发。

[![Stars](https://img.shields.io/github/stars/vureact-js/core?style=flat-square&color=magenta)](https://github.com/vureact-js/core)
[![Stars](https://img.shields.io/github/stars/vureact-js/core?style=flat-square&color=magenta)](https://github.com/vureact-js/core/stargazers)
[![Downloads](https://img.shields.io/npm/dt/@vureact/compiler-core?label=Downloads&style=flat-square)](https://www.npmjs.com/package/@vureact/compiler-core)
[![Node](https://img.shields.io/badge/node-%3E%3D19.0.0-green?label=Node)](https://nodejs.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/vureact-js/core/blob/master/LICENSE)
Expand Down
4 changes: 2 additions & 2 deletions packages/compiler-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vureact/compiler-core",
"version": "1.8.4",
"version": "1.8.5",
"description": "Migrate Vue to React, or write React in Vue syntax.",
"author": "Ruihong Zhong (Ryan John)",
"license": "MIT",
Expand Down Expand Up @@ -99,4 +99,4 @@
"engines": {
"node": ">=19.0.0"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function buildJSX(
nodeIR: TemplateBlockIR | null,
ctx: ICompilationContext,
): JSXChild | null {
if (!nodeIR?.children.length) {
if (!nodeIR?.children.length && ctx.inputType !== 'sfc') {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ export type JsxProcessor = (
state: JsxBuildState,
) => void;

export function buildJSXChild(nodeIR: TemplateBlockIR, ctx: ICompilationContext): JSXChild | null {
export function buildJSXChild(
nodeIR: TemplateBlockIR | null,
ctx: ICompilationContext,
): JSXChild | null {
const templateIR = nodeIR || { children: [] };
const state: JsxBuildState = {
rootChildren: [],
result: null,
};

jsxBuilder(nodeIR, ctx, state, {
jsxBuilder(templateIR, ctx, state, {
preprocess: [],
process: [buildJsxChildrenProcessor],
postprocess: [buildRootJsxProcessor],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { JSXElement, JSXFragment } from '@babel/types';
import { ICompilationContext } from '@compiler/context/types';
import { TemplateBlockIR } from '@src/core/transform/sfc/template';
import { JsxBuildState } from '..';
Expand All @@ -9,19 +10,37 @@ export function buildRootJsxProcessor(
ctx: ICompilationContext,
state: JsxBuildState,
) {
if (!state.rootChildren.length) {
state.result = null;
const { rootChildren } = state;
const { provide } = ctx.scriptData;

const hasProvide = provide.isOccupied;
const hasChildren = rootChildren.length > 0; // 是否有任意 jsx 节点

const setResult = (elem?: JSXElement | JSXFragment) => {
state.result = elem ?? null;
};

// 如果存在上下文提供者
if (hasProvide) {
const provider = buildCtxProviderNode(provide, ctx, rootChildren);

// fix: https://github.com/vureact-js/core/issues/51
if (!hasChildren) {
// 根节点没有 children 时,创建一个包含提供者的片段节点
setResult(buildFragmentNode([provider]));
} else {
setResult(provider);
}

return;
}

const { provide } = ctx.scriptData;

if (provide.isOccupied) {
state.result = buildCtxProviderNode(provide, ctx, state.rootChildren);
if (!hasChildren) {
setResult();
return;
}

state.result = buildFragmentNode(state.rootChildren);
setResult(buildFragmentNode(rootChildren));

void nodeIR;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { generate } from '@babel/generator';
import { createCompilationCtx } from '@compiler/context';
import { parseSFC } from '@core/parse';
import { logger } from '@shared/logger';
import { getDirname } from '@shared/path';
import { transform } from '@src/core/transform/sfc';
import { generate, parseSFC, transform } from '@src/core';
import { readFileSync, writeFileSync } from 'fs';
import path from 'path';

Expand All @@ -23,7 +21,7 @@ function testTransformApi() {
console.timeEnd('testTransformApi transform duration');
console.log();

const code = generate(result.script.statement.local!).code;
const code = generate(result, ctx.data).code;

writeFileSync(path.join(__dirname, './preview.jsx'), code, 'utf-8');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
<script setup>
import { computed, onBeforeMount, onUpdated, reactive, ref, watch, watchEffect } from 'vue';
import {
computed,
onBeforeMount,
onUpdated,
provide,
reactive,
ref,
watch,
watchEffect,
} from 'vue';

const count = ref(1);
const state = reactive({ count: 1 });
Expand Down Expand Up @@ -31,4 +40,9 @@ watchEffect((onCleanup) => {
onCleanup(() => {});
result.value;
});

provide(batchActionContextKey, {
queue: computed(() => filters.value.queue),
status: computed(() => filters.value.status),
});
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,10 @@ export function processVueSyntax(ast: BabelParseResult, ctx: ICompilationContext
process: {
applyBabel: [
resolveElementRef,
// provide 需要在 rename 之前收集并移除原始调用,避免被重命名后失配
resolveProvide,
resolveRenameAdapter,
// fix:在分析函数前分析可优化为 useMemo 的顶层变量声明,
// 使得后续能够被函数依赖分析
// fix: https://github.com/vureact-js/core/issues/46
resolveProvide,
// fix:在分析函数前分析可优化为 useMemo 的顶层变量声明,使得后续能够被函数依赖分析
resolveExprMemo,
resolveArrowFnDeps,
resolveAnalysisOnlyAdapter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as t from '@babel/types';
import { ICompilationContext, ProvideData } from '@compiler/context/types';
import { ADAPTER_RULES } from '@consts/adapters-map';
import { VUE_API_MAP } from '@consts/vue-api-map';
import { logger } from '@shared/logger';
import { recordImport } from '@transform/shared';
import { isCalleeNamed } from '../../shared/babel-utils';

Expand All @@ -14,21 +15,38 @@ type ArgumentType = t.Expression | t.SpreadElement | t.ArgumentPlaceholder;
* 在生成阶段根据 AST 生成对应结构的 CtxProvider 适配组件
*/
export function resolveProvide(ctx: ICompilationContext): TraverseOptions {
const { filename, scriptData, inputType } = ctx;

// 仅跳过纯样式文件,脚本输入也允许处理 provide
if (ctx.inputType === 'style') return {};
if (inputType !== 'sfc') {
return {};
}

return {
CallExpression(path) {
const { node } = path;

// 不允许在 script 文件中使用 provide
if (inputType.startsWith('script')) {
logger.error('provide() call found outside of SFC <script setup> context.', {
file: filename,
source: scriptData.source,
loc: node.loc,
});
return;
}

// 检查是否为 provide 调用(兼容已被重命名为 Provider 的场景)
const providerTarget = ADAPTER_RULES.runtime[VUE_API_MAP.provide]?.target;

const isProvideCall =
isCalleeNamed(node, VUE_API_MAP.provide) || (providerTarget && isCalleeNamed(node, providerTarget));
isCalleeNamed(node, VUE_API_MAP.provide) ||
(providerTarget && isCalleeNamed(node, providerTarget));

if (!isProvideCall) return;

// 获取编译上下文中的 provide 数据
const { provide } = ctx.scriptData;
const { provide } = scriptData;

// 提取 provide 的参数:key 和 value
const [key, value] = node.arguments;
Expand Down
Loading