@vitarx/plugin-vite 0.0.1-beta.5 → 0.0.1-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -249,10 +249,42 @@ import.meta.hot.accept(mod => {
249
249
 
250
250
  ```typescript
251
251
  interface VitePluginVitarxOptions {
252
- // 暂无配置选项
252
+ /**
253
+ * 是否将 className 属性转换为 class 属性
254
+ * 仅对原生 HTML 元素生效,组件不生效
255
+ * @default false
256
+ */
257
+ transformClassNameToClass?: boolean
253
258
  }
254
259
  ```
255
260
 
261
+ ### className 转 class
262
+
263
+ 启用 `transformClassNameToClass` 选项后,原生 HTML 元素的 `className` 属性会自动转换为 `class`:
264
+
265
+ ```typescript
266
+ // vite.config.ts
267
+ import { defineConfig } from 'vite'
268
+ import vitarx from '@vitarx/plugin-vite'
269
+
270
+ export default defineConfig({
271
+ plugins: [vitarx({ transformClassNameToClass: true })]
272
+ })
273
+ ```
274
+
275
+ ```jsx
276
+ // 编译前
277
+ <div className="container">Hello</div>
278
+
279
+ // 编译后
280
+ createView('div', { class: 'container', children: 'Hello' })
281
+ ```
282
+
283
+ **注意事项:**
284
+ - 仅对原生 HTML 元素(小写字母开头)生效,组件不转换
285
+ - `class` 和 `className` 不能同时存在,否则会抛出 `E016` 错误
286
+ - `class` 属性优先级更高
287
+
256
288
  ## 目录结构
257
289
 
258
290
  ```
@@ -292,6 +324,7 @@ src/
292
324
  | E013 | Match 组件必须包含子元素 |
293
325
  | E014 | IfBlock 组件必须包含子元素 |
294
326
  | E015 | Switch 组件必须包含至少一个 Match 子元素 |
327
+ | E016 | class 和 className 不能同时存在 |
295
328
 
296
329
  ## License
297
330
 
package/dist/context.d.ts CHANGED
@@ -4,15 +4,8 @@
4
4
  * @module context
5
5
  */
6
6
  import type { File } from '@babel/types';
7
- import type { CompileOptions } from './transform.js';
8
7
  import type { CompilerWarning } from './error.js';
9
- import { UI_API_NAMES } from './constants/index.js';
10
- /**
11
- * UI 相关的 API 名称列表
12
- * 这些 API 用于创建视图,在 HMR 时需要识别
13
- */
14
- export declare const UI_API_NAMES_CONST: readonly ["createView", "branch", "dynamic", "access", "withDirectives"];
15
- export type UIApiName = (typeof UI_API_NAMES)[number];
8
+ import type { CompileOptions } from './transform.js';
16
9
  /**
17
10
  * 导入信息
18
11
  * 追踪需要注入的运行时 API
@@ -105,12 +98,6 @@ export declare function createContext(code: string, id: string, options: Compile
105
98
  * @param name - 导入名称
106
99
  */
107
100
  export declare function markImport(ctx: TransformContext, name: keyof ImportInfo): void;
108
- /**
109
- * 记录 UI API 别名
110
- * @param ctx - 转换上下文
111
- * @param alias - API 别名
112
- */
113
- export declare function markUiApiAlias(ctx: TransformContext, alias: string): void;
114
101
  /**
115
102
  * 添加编译警告
116
103
  * @param ctx - 转换上下文
package/dist/context.js CHANGED
@@ -1,9 +1,3 @@
1
- import { UI_API_NAMES } from './constants/index.js';
2
- /**
3
- * UI 相关的 API 名称列表
4
- * 这些 API 用于创建视图,在 HMR 时需要识别
5
- */
6
- export const UI_API_NAMES_CONST = UI_API_NAMES;
7
1
  /**
8
2
  * 创建转换上下文
9
3
  * @param code - 源代码
@@ -61,14 +55,6 @@ export function createContext(code, id, options, ast) {
61
55
  export function markImport(ctx, name) {
62
56
  ctx.imports[name] = true;
63
57
  }
64
- /**
65
- * 记录 UI API 别名
66
- * @param ctx - 转换上下文
67
- * @param alias - API 别名
68
- */
69
- export function markUiApiAlias(ctx, alias) {
70
- ctx.uiApiAliases.add(alias);
71
- }
72
58
  /**
73
59
  * 添加编译警告
74
60
  * @param ctx - 转换上下文
package/dist/error.d.ts CHANGED
@@ -71,6 +71,8 @@ export declare const ErrorCodes: {
71
71
  readonly E014: "E014";
72
72
  /** Switch 组件必须有 Match 子元素 */
73
73
  readonly E015: "E015";
74
+ /** class 和 className 不能同时存在 */
75
+ readonly E016: "E016";
74
76
  };
75
77
  /**
76
78
  * 警告代码枚举
package/dist/error.js CHANGED
@@ -61,6 +61,8 @@ export const ErrorCodes = {
61
61
  E014: 'E014',
62
62
  /** Switch 组件必须有 Match 子元素 */
63
63
  E015: 'E015',
64
+ /** class 和 className 不能同时存在 */
65
+ E016: 'E016',
64
66
  };
65
67
  /**
66
68
  * 警告代码枚举
@@ -88,6 +90,7 @@ export const ErrorMessages = {
88
90
  E013: 'Match component must have children',
89
91
  E014: 'IfBlock component must have children',
90
92
  E015: 'Switch component must have at least one Match child',
93
+ E016: 'Cannot use both "class" and "className" attributes on the same element. When transformClassNameToClass is enabled, "class" takes priority',
91
94
  };
92
95
  /**
93
96
  * 警告消息映射
@@ -124,7 +124,7 @@ class HMRManager {
124
124
  if (id)
125
125
  __classPrivateFieldGet(this, _HMRManager_idMapToComponent, "f").set(id, newComponent);
126
126
  // 更新节点视图
127
- if (node.active && node.isMounted) {
127
+ if ((node.isActive || node.active) && node.isMounted) {
128
128
  processUpdate(node, newComponent);
129
129
  }
130
130
  }
@@ -10,7 +10,7 @@ import { UI_API_NAMES } from '../constants/index.js';
10
10
  * UI 相关的运行时 API 名称
11
11
  * 这些 API 调用代表 UI 描述代码
12
12
  */
13
- const UI_APIS = new Set([...UI_API_NAMES, 'jsxDEV']);
13
+ const UI_APIS = new Set([...UI_API_NAMES, 'jsxDEV', 'h']);
14
14
  /**
15
15
  * 判断标识符名称是否为 UI API
16
16
  * 支持原始名称和带后缀的名称(如 jsxDEV$1)
package/dist/index.d.ts CHANGED
@@ -2,10 +2,19 @@ import { type Plugin } from 'vite';
2
2
  export type * from './types.js';
3
3
  /**
4
4
  * vite-plugin-vitarx 配置选项
5
- *
6
- * 暂无配置选项
7
5
  */
8
6
  export interface VitePluginVitarxOptions {
7
+ /**
8
+ * 是否将 className 属性转换为 class 属性
9
+ * 仅对原生 HTML 元素生效,组件不生效
10
+ *
11
+ * 当启用时:
12
+ * - `<div className="test" />` 转换为 `<div class="test" />`
13
+ * - 如果同时存在 class 和 className,会抛出错误(class 优先级更高)
14
+ *
15
+ * @default false
16
+ */
17
+ transformClassNameToClass?: boolean;
9
18
  }
10
19
  /**
11
20
  * vite-plugin-vitarx
@@ -15,8 +24,9 @@ export interface VitePluginVitarxOptions {
15
24
  * - 支持 v-if、v-else-if、v-else 、v-model 等编译宏指令
16
25
  * - 支持 Switch , IfBlock 等编译宏组件
17
26
  * - 开发时 HMR 热更新相关代码注入与功能支持
27
+ * - 支持 className 转 class(仅原生 HTML 元素)
18
28
  *
19
- * @param _options - 暂无可选配置。
29
+ * @param options - 插件配置选项。
20
30
  * @returns - vite插件对象。
21
31
  */
22
- export default function vitarx(_options?: VitePluginVitarxOptions): Plugin;
32
+ export default function vitarx(options?: VitePluginVitarxOptions): Plugin;
package/dist/index.js CHANGED
@@ -20,11 +20,12 @@ else {
20
20
  * - 支持 v-if、v-else-if、v-else 、v-model 等编译宏指令
21
21
  * - 支持 Switch , IfBlock 等编译宏组件
22
22
  * - 开发时 HMR 热更新相关代码注入与功能支持
23
+ * - 支持 className 转 class(仅原生 HTML 元素)
23
24
  *
24
- * @param _options - 暂无可选配置。
25
+ * @param options - 插件配置选项。
25
26
  * @returns - vite插件对象。
26
27
  */
27
- export default function vitarx(_options) {
28
+ export default function vitarx(options) {
28
29
  let compileOptions;
29
30
  let isDEV = false;
30
31
  let isSSR = false;
@@ -35,11 +36,7 @@ export default function vitarx(_options) {
35
36
  isDEV = env.command === 'serve' && !env.isPreview;
36
37
  const configSSR = !!config.build?.ssr;
37
38
  isSSR = env.isSsrBuild === true || configSSR;
38
- const buildConfig = {
39
- jsx: 'preserve',
40
- exclude: /\.[jt]sx$/
41
- };
42
- const _config = {
39
+ return {
43
40
  define: {
44
41
  __VITARX_DEV__: JSON.stringify(isDEV),
45
42
  __VITARX_SSR__: JSON.stringify(isSSR)
@@ -48,10 +45,11 @@ export default function vitarx(_options) {
48
45
  alias: {
49
46
  '@vitarx/vite-plugin/hmr-client': path.join(__dirname, 'hmr-client/index.js')
50
47
  }
48
+ },
49
+ [IS_V8 ? 'oxc' : 'esbuild']: {
50
+ jsx: 'preserve'
51
51
  }
52
52
  };
53
- _config[IS_V8 ? 'oxc' : 'esbuild'] = buildConfig;
54
- return _config;
55
53
  },
56
54
  configResolved(config) {
57
55
  viteConfig = config;
@@ -60,14 +58,15 @@ export default function vitarx(_options) {
60
58
  ssr: isSSR,
61
59
  hmr: isDEV && !isSSR,
62
60
  runtimeModule: 'vitarx',
63
- sourceMap: false
61
+ sourceMap: true,
62
+ transformClassNameToClass: options?.transformClassNameToClass ?? false
64
63
  };
65
64
  },
66
65
  async transform(code, id) {
67
66
  const result = await transform(code, id, compileOptions);
68
67
  if (!result)
69
68
  return null;
70
- return await viteTransform(result.code, id, undefined, this.getCombinedSourcemap(), viteConfig);
69
+ return viteTransform(result.code, id, undefined, result.map || undefined, viteConfig);
71
70
  }
72
71
  };
73
72
  }
@@ -19,12 +19,33 @@ export declare function processSpreadAttribute(attr: t.JSXSpreadAttribute, hasVB
19
19
  property: t.ObjectProperty;
20
20
  hasVBind: boolean;
21
21
  } | null;
22
+ /**
23
+ * 获取属性值表达式
24
+ * 处理不同类型的属性值,统一返回表达式
25
+ * @param value - JSX 属性值
26
+ * @returns 表达式节点
27
+ */
28
+ export declare function getAttributeValue(value: t.JSXAttribute['value']): t.Expression;
29
+ /**
30
+ * 创建对象属性节点
31
+ * 静态值直接赋值,动态值生成 getter 方法
32
+ *
33
+ * 特殊处理:
34
+ * - children 属性不使用 unref,因为 ref 作为 children 是合法的可变渲染源
35
+ * - 其他标识符属性使用 unref 解包
36
+ *
37
+ * @param key - 属性名
38
+ * @param value - 属性值表达式
39
+ * @param ctx - 转换上下文
40
+ * @returns 对象属性或方法节点
41
+ */
42
+ export declare function createProperty(key: string, value: t.Expression, ctx: TransformContext): t.ObjectProperty | t.ObjectMethod;
22
43
  /**
23
44
  * 处理单个 JSX 属性
24
45
  * 根据属性名类型分发到不同的处理逻辑
25
46
  * @param attr - JSX 属性节点
26
47
  * @param existingPropNames - 已存在的属性名集合
27
48
  * @param ctx - 转换上下文
28
- * @returns 属性处理结果
49
+ * @returns - 属性处理结果
29
50
  */
30
51
  export declare function processAttribute(attr: t.JSXAttribute, existingPropNames: Set<string>, ctx: TransformContext): AttributeResult;
@@ -27,48 +27,6 @@ export function processSpreadAttribute(attr, hasVBind, node) {
27
27
  hasVBind: true
28
28
  };
29
29
  }
30
- /**
31
- * 处理单个 JSX 属性
32
- * 根据属性名类型分发到不同的处理逻辑
33
- * @param attr - JSX 属性节点
34
- * @param existingPropNames - 已存在的属性名集合
35
- * @param ctx - 转换上下文
36
- * @returns 属性处理结果
37
- */
38
- export function processAttribute(attr, existingPropNames, ctx) {
39
- const attrName = attr.name;
40
- // 处理命名空间属性 (v:xxx)
41
- if (attrName.type === 'JSXNamespacedName') {
42
- return processNamespacedAttribute(attr, attrName, existingPropNames, ctx);
43
- }
44
- // 处理标识符属性
45
- if (attrName.type === 'JSXIdentifier') {
46
- const name = attrName.name;
47
- // v-bind 指令
48
- if (name === 'v-bind') {
49
- const value = getAttributeValue(attr.value);
50
- return { type: 'directive', name: 'v-bind', value, isVBind: true, isVModel: false };
51
- }
52
- // v-model 指令
53
- if (name === 'v-model') {
54
- const value = getAttributeValue(attr.value);
55
- return { type: 'directive', name: 'v-model', value, isVBind: false, isVModel: true };
56
- }
57
- // 其他 v- 指令(排除 v-if 系列,它们在单独的处理流程中)
58
- if (name.startsWith('v-') && !['v-if', 'v-else-if', 'v-else'].includes(name)) {
59
- const value = getAttributeValue(attr.value);
60
- return { type: 'directive', name, value, isVBind: false, isVModel: false };
61
- }
62
- // 普通属性
63
- existingPropNames.add(name);
64
- const value = getAttributeValue(attr.value);
65
- const property = createProperty(name, value, ctx);
66
- return { type: 'property', property };
67
- }
68
- // 未知属性类型,作为普通属性处理
69
- const value = getAttributeValue(attr.value);
70
- return { type: 'property', property: t.objectProperty(t.identifier('unknown'), value) };
71
- }
72
30
  /**
73
31
  * 处理命名空间属性
74
32
  *
@@ -109,18 +67,14 @@ function processNamespacedAttribute(attr, attrName, existingPropNames, ctx) {
109
67
  * @param value - JSX 属性值
110
68
  * @returns 表达式节点
111
69
  */
112
- function getAttributeValue(value) {
113
- // 无值属性默认为 true
70
+ export function getAttributeValue(value) {
114
71
  if (!value) {
115
72
  return t.booleanLiteral(true);
116
73
  }
117
- // 字符串字面量直接返回
118
74
  if (isStringLiteral(value)) {
119
75
  return value;
120
76
  }
121
- // JSX 表达式容器
122
77
  if (isJSXExpressionContainer(value)) {
123
- // 空表达式 {} 视为 true
124
78
  if (value.expression.type === 'JSXEmptyExpression') {
125
79
  return t.booleanLiteral(true);
126
80
  }
@@ -141,7 +95,7 @@ function getAttributeValue(value) {
141
95
  * @param ctx - 转换上下文
142
96
  * @returns 对象属性或方法节点
143
97
  */
144
- function createProperty(key, value, ctx) {
98
+ export function createProperty(key, value, ctx) {
145
99
  const keyNode = t.stringLiteral(key);
146
100
  if (isStringLiteral(value) || isNumericLiteral(value) || isBooleanLiteral(value)) {
147
101
  return t.objectProperty(keyNode, value);
@@ -159,3 +113,45 @@ function createProperty(key, value, ctx) {
159
113
  }
160
114
  return t.objectMethod('get', keyNode, [], t.blockStatement([t.returnStatement(value)]));
161
115
  }
116
+ /**
117
+ * 处理单个 JSX 属性
118
+ * 根据属性名类型分发到不同的处理逻辑
119
+ * @param attr - JSX 属性节点
120
+ * @param existingPropNames - 已存在的属性名集合
121
+ * @param ctx - 转换上下文
122
+ * @returns - 属性处理结果
123
+ */
124
+ export function processAttribute(attr, existingPropNames, ctx) {
125
+ const attrName = attr.name;
126
+ // 处理命名空间属性 (v:xxx)
127
+ if (attrName.type === 'JSXNamespacedName') {
128
+ return processNamespacedAttribute(attr, attrName, existingPropNames, ctx);
129
+ }
130
+ // 处理标识符属性
131
+ if (attrName.type === 'JSXIdentifier') {
132
+ const name = attrName.name;
133
+ // v-bind 指令
134
+ if (name === 'v-bind') {
135
+ const value = getAttributeValue(attr.value);
136
+ return { type: 'directive', name: 'v-bind', value, isVBind: true, isVModel: false };
137
+ }
138
+ // v-model 指令
139
+ if (name === 'v-model') {
140
+ const value = getAttributeValue(attr.value);
141
+ return { type: 'directive', name: 'v-model', value, isVBind: false, isVModel: true };
142
+ }
143
+ // 其他 v- 指令(排除 v-if 系列,它们在单独的处理流程中)
144
+ if (name.startsWith('v-') && !['v-if', 'v-else-if', 'v-else'].includes(name)) {
145
+ const value = getAttributeValue(attr.value);
146
+ return { type: 'directive', name, value, isVBind: false, isVModel: false };
147
+ }
148
+ // 普通属性
149
+ existingPropNames.add(name);
150
+ const value = getAttributeValue(attr.value);
151
+ const property = createProperty(name, value, ctx);
152
+ return { type: 'property', property };
153
+ }
154
+ // 未知属性类型,作为普通属性处理
155
+ const value = getAttributeValue(attr.value);
156
+ return { type: 'property', property: t.objectProperty(t.identifier('unknown'), value) };
157
+ }
@@ -6,7 +6,7 @@
6
6
  import * as t from '@babel/types';
7
7
  import { TransformContext } from '../../context.js';
8
8
  import type { PropsResult } from './types.js';
9
- export type { PropsResult, VModelState, AttributeResult } from './types.js';
9
+ export type { AttributeResult, PropsResult, VModelState } from './types.js';
10
10
  /**
11
11
  * 处理 JSX 元素的属性
12
12
  * 将 JSX 属性转换为运行时 props 对象,并提取指令
@@ -17,6 +17,7 @@ export type { PropsResult, VModelState, AttributeResult } from './types.js';
17
17
  * 3. 普通属性转换为对象属性或 getter
18
18
  * 4. 指令属性提取到 directives Map
19
19
  * 5. v-model 特殊处理,生成 modelValue 和 onUpdate:modelValue
20
+ * 6. className 转 class(仅原生元素,启用 transformClassNameToClass 时)
20
21
  *
21
22
  * @param node - JSX 元素节点
22
23
  * @param ctx - 转换上下文
@@ -4,8 +4,39 @@
4
4
  * @module passes/props
5
5
  */
6
6
  import * as t from '@babel/types';
7
- import { processAttribute, processSpreadAttribute } from './attribute.js';
7
+ import { createError } from '../../error.js';
8
+ import { isNativeElement } from '../../utils/index.js';
9
+ import { createProperty, getAttributeValue, processAttribute, processSpreadAttribute } from './attribute.js';
8
10
  import { createVModelProps, extractVModelState } from './vmodel.js';
11
+ /**
12
+ * 获取 JSX 元素的名称
13
+ */
14
+ function getJSXElementName(node) {
15
+ const nameNode = node.openingElement.name;
16
+ return nameNode.type === 'JSXIdentifier' ? nameNode.name : null;
17
+ }
18
+ /**
19
+ * 校验 class 和 className 不能同时存在
20
+ */
21
+ function validateClassAndClassName(attributes) {
22
+ let hasClass = false;
23
+ let hasClassName = false;
24
+ let classNameAttr;
25
+ for (const attr of attributes) {
26
+ if (attr.type === 'JSXAttribute' && attr.name.type === 'JSXIdentifier') {
27
+ if (attr.name.name === 'class') {
28
+ hasClass = true;
29
+ }
30
+ else if (attr.name.name === 'className') {
31
+ hasClassName = true;
32
+ classNameAttr = attr;
33
+ }
34
+ }
35
+ }
36
+ if (hasClass && hasClassName) {
37
+ throw createError('E016', classNameAttr);
38
+ }
39
+ }
9
40
  /**
10
41
  * 处理 JSX 元素的属性
11
42
  * 将 JSX 属性转换为运行时 props 对象,并提取指令
@@ -16,6 +47,7 @@ import { createVModelProps, extractVModelState } from './vmodel.js';
16
47
  * 3. 普通属性转换为对象属性或 getter
17
48
  * 4. 指令属性提取到 directives Map
18
49
  * 5. v-model 特殊处理,生成 modelValue 和 onUpdate:modelValue
50
+ * 6. className 转 class(仅原生元素,启用 transformClassNameToClass 时)
19
51
  *
20
52
  * @param node - JSX 元素节点
21
53
  * @param ctx - 转换上下文
@@ -45,6 +77,14 @@ export function processProps(node, ctx, hasChildren = false) {
45
77
  const existingPropNames = new Set();
46
78
  // 提取初始 v-model 状态
47
79
  let vModelState = extractVModelState(attributes);
80
+ // 获取元素名称,用于判断是否为原生元素
81
+ const elementName = getJSXElementName(node);
82
+ const isNative = elementName ? isNativeElement(elementName) : false;
83
+ // 检查是否启用 className 转 class 且为原生元素
84
+ const shouldTransformClassName = ctx.options.transformClassNameToClass && isNative;
85
+ // 如果启用 className 转 class,先检测 class 和 className 冲突
86
+ if (shouldTransformClassName)
87
+ validateClassAndClassName(attributes);
48
88
  // 遍历处理所有属性
49
89
  for (const attr of attributes) {
50
90
  // 处理展开属性 {...props}
@@ -62,6 +102,16 @@ export function processProps(node, ctx, hasChildren = false) {
62
102
  if (hasChildren && attr.name.type === 'JSXIdentifier' && attr.name.name === 'children') {
63
103
  continue;
64
104
  }
105
+ // 如果启用 className 转 class,处理 className 属性
106
+ if (shouldTransformClassName &&
107
+ attr.name.type === 'JSXIdentifier' &&
108
+ attr.name.name === 'className') {
109
+ const value = getAttributeValue(attr.value);
110
+ const property = createProperty('class', value, ctx);
111
+ properties.push(property);
112
+ existingPropNames.add('class');
113
+ continue;
114
+ }
65
115
  const result = processAttribute(attr, existingPropNames, ctx);
66
116
  if (result.type === 'directive') {
67
117
  // v-model 指令:更新状态
@@ -1,6 +1,10 @@
1
- export interface TransformResult {
2
- code: string;
3
- map: any;
1
+ /**
2
+ * 主转换模块
3
+ * 负责解析 JSX/TSX 代码并转换为 createView 调用
4
+ * @module transform
5
+ */
6
+ import { type GeneratorResult } from '@babel/generator';
7
+ export interface TransformResult extends GeneratorResult {
4
8
  }
5
9
  export interface CompileOptions {
6
10
  hmr: boolean;
@@ -8,6 +12,7 @@ export interface CompileOptions {
8
12
  ssr: boolean;
9
13
  runtimeModule: string;
10
14
  sourceMap: boolean | 'inline' | 'both';
15
+ transformClassNameToClass: boolean;
11
16
  }
12
17
  /**
13
18
  * 转换 JSX/TSX 代码
package/dist/transform.js CHANGED
@@ -15,8 +15,6 @@ const processedNodes = new WeakSet();
15
15
  * 检查文件是否需要转换
16
16
  */
17
17
  function shouldTransform(id) {
18
- if (id.includes('node_modules'))
19
- return false;
20
18
  const ext = id.split('?')[0].split('.').pop()?.toLowerCase();
21
19
  return ext === 'jsx' || ext === 'tsx';
22
20
  }
@@ -121,8 +119,8 @@ function transformAST(ast, ctx) {
121
119
  */
122
120
  function generateCode(ast, code, id, sourceMap) {
123
121
  const babelGenerate = typeof generate === 'object' ? generate.default : generate;
124
- const output = babelGenerate(ast, { sourceMaps: !!sourceMap, filename: id }, code);
125
- return { code: output.code, map: output.map || undefined };
122
+ const output = babelGenerate(ast, { sourceMaps: !!sourceMap, filename: id, sourceFileName: id }, code);
123
+ return { code: output.code, map: output.map };
126
124
  }
127
125
  /**
128
126
  * 转换 JSX/TSX 代码
@@ -4,10 +4,8 @@
4
4
  * @module passes/transform/collect
5
5
  */
6
6
  import * as t from '@babel/types';
7
- import { DEFAULT_EXPORT_BASE_NAME, PURE_COMPILE_COMPONENTS } from '../constants/index.js';
7
+ import { DEFAULT_EXPORT_BASE_NAME } from '../constants/index.js';
8
8
  import { generateUniqueAlias } from './generate.js';
9
- /** 纯编译组件名称集合 */
10
- const PURE_COMPILE_COMPONENT_SET = new Set(PURE_COMPILE_COMPONENTS);
11
9
  /**
12
10
  * 生成唯一的默认导出组件名称
13
11
  * 避免与已存在的名称冲突
@@ -62,54 +60,8 @@ function collectFromDefaultExport(node, names) {
62
60
  }
63
61
  // 匿名函数不在此处预留名称,而是在处理时动态生成唯一名称
64
62
  }
65
- /**
66
- * 检查函数是否为组件函数
67
- * 通过遍历 AST 检查是否包含 JSX 元素
68
- */
69
- function isComponentFunction(node) {
70
- let result = false;
71
- const check = (n) => {
72
- if (result)
73
- return;
74
- // 直接包含 JSX 元素
75
- if (n.type === 'JSXElement' || n.type === 'JSXFragment') {
76
- result = true;
77
- return;
78
- }
79
- // 检查 return 语句中的纯编译组件
80
- if (n.type === 'ReturnStatement' && n.argument?.type === 'JSXElement') {
81
- const opening = n.argument.openingElement;
82
- if (opening.name.type === 'JSXIdentifier' &&
83
- PURE_COMPILE_COMPONENT_SET.has(opening.name.name)) {
84
- result = true;
85
- return;
86
- }
87
- }
88
- // 递归遍历子节点
89
- for (const key of Object.keys(n)) {
90
- const child = n[key];
91
- if (child && typeof child === 'object') {
92
- if (Array.isArray(child)) {
93
- for (const c of child) {
94
- if (c && typeof child === 'object')
95
- check(c);
96
- }
97
- }
98
- else {
99
- check(child);
100
- }
101
- }
102
- }
103
- };
104
- check(node);
105
- return result;
106
- }
107
- /**
108
- * 尝试添加组件到列表
109
- * 检查名称有效性、是否导出、是否为组件函数
110
- */
111
63
  function tryAddComponent(name, node, exportedNames, components) {
112
- if (isValidComponentName(name) && exportedNames.has(name) && isComponentFunction(node)) {
64
+ if (isValidComponentName(name) && exportedNames.has(name)) {
113
65
  components.push({ name, node });
114
66
  }
115
67
  }
@@ -149,26 +101,17 @@ function processAnonymousDefaultExport(node, exportedNames, components) {
149
101
  const decl = node.declaration;
150
102
  let funcNode = null;
151
103
  let name;
152
- // 匿名函数声明
153
104
  if (decl.type === 'FunctionDeclaration' && !decl.id) {
154
- if (!isComponentFunction(decl))
155
- return;
156
105
  name = generateUniqueDefaultName(exportedNames);
157
106
  decl.id = t.identifier(name);
158
107
  funcNode = decl;
159
108
  }
160
- // 函数表达式
161
109
  else if (decl.type === 'FunctionExpression') {
162
- if (!isComponentFunction(decl))
163
- return;
164
110
  name = generateUniqueDefaultName(exportedNames);
165
111
  funcNode = convertToNamedFunctionDeclaration(decl, name);
166
112
  node.declaration = funcNode;
167
113
  }
168
- // 箭头函数
169
114
  else if (decl.type === 'ArrowFunctionExpression') {
170
- if (!isComponentFunction(decl))
171
- return;
172
115
  name = generateUniqueDefaultName(exportedNames);
173
116
  funcNode = convertToNamedFunctionDeclaration(decl, name);
174
117
  node.declaration = funcNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitarx/plugin-vite",
3
- "version": "0.0.1-beta.5",
3
+ "version": "0.0.1-beta.7",
4
4
  "description": "The official plugin for Vitarx support in Vite.",
5
5
  "author": "ZhuChongLin <8210856@qq.com>",
6
6
  "license": "MIT",
@@ -52,7 +52,9 @@
52
52
  "node": "^25.7.0",
53
53
  "prettier": "^3.8.1",
54
54
  "rimraf": "^6.1.3",
55
- "vitest": "^4.0.18"
55
+ "vitest": "^4.0.18",
56
+ "vite": "^8.0.2",
57
+ "vitarx": "^4.0.0-beta.8"
56
58
  },
57
59
  "scripts": {
58
60
  "build": "rimraf dist && tsc",