@vitarx/plugin-vite 0.0.1-beta.7 → 1.0.0-beta.0

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.
Files changed (41) hide show
  1. package/README.md +64 -4
  2. package/dist/constants/index.d.ts +1 -11
  3. package/dist/constants/index.js +1 -11
  4. package/dist/context.d.ts +14 -10
  5. package/dist/context.js +7 -5
  6. package/dist/hmr-client/index.d.ts +2 -1
  7. package/dist/hmr-client/index.js +3 -2
  8. package/dist/hmr-client/utils.d.ts +1 -1
  9. package/dist/hmr-client/utils.js +7 -4
  10. package/dist/index.js +10 -4
  11. package/dist/passes/components/ifBlock.js +2 -4
  12. package/dist/passes/components/switch.js +2 -4
  13. package/dist/passes/directives/processDirectives.js +1 -1
  14. package/dist/passes/directives/vIf.js +2 -5
  15. package/dist/passes/hmr/inject-imports.d.ts +19 -0
  16. package/dist/passes/hmr/inject-imports.js +26 -0
  17. package/dist/passes/hmr/inject-state.d.ts +29 -0
  18. package/dist/passes/hmr/inject-state.js +101 -0
  19. package/dist/passes/hmr/inject.d.ts +1 -1
  20. package/dist/passes/hmr/inject.js +13 -123
  21. package/dist/passes/imports/injectImports.js +2 -2
  22. package/dist/passes/jsx/processChildren.js +30 -51
  23. package/dist/passes/jsx/processJSXElement.js +3 -6
  24. package/dist/passes/jsx/processJSXFragment.js +4 -4
  25. package/dist/passes/props/index.js +1 -8
  26. package/dist/transform.d.ts +5 -8
  27. package/dist/transform.js +19 -20
  28. package/dist/types.d.ts +11 -0
  29. package/dist/utils/ast-builders.d.ts +18 -18
  30. package/dist/utils/ast-builders.js +27 -41
  31. package/dist/utils/branch-factory.d.ts +1 -4
  32. package/dist/utils/branch-factory.js +4 -7
  33. package/dist/utils/collect-names.d.ts +37 -0
  34. package/dist/utils/collect-names.js +129 -0
  35. package/dist/utils/component-collect.d.ts +9 -4
  36. package/dist/utils/component-collect.js +64 -74
  37. package/dist/utils/index.d.ts +2 -2
  38. package/dist/utils/index.js +2 -2
  39. package/dist/utils/jsx-helpers.d.ts +3 -2
  40. package/dist/utils/jsx-helpers.js +3 -2
  41. package/package.json +11 -4
@@ -5,133 +5,28 @@
5
5
  */
6
6
  import * as t from '@babel/types';
7
7
  import { HMR } from '../../constants/index.js';
8
- import { collectPatternBindings } from '../../utils/index.js';
9
- /** getComponentView 的内部别名,避免与用户代码冲突 */
10
- const GET_COMPONENT_VIEW_ALIAS = '__$VITARX_GET_COMPONENT_VIEW$__';
11
- /**
12
- * 注入 HMR 客户端导入
13
- * @param program - AST Program 节点
14
- */
15
- function injectHMRImport(program) {
16
- const importDecl = t.importDeclaration([t.importDefaultSpecifier(t.identifier(HMR.manager))], t.stringLiteral('@vitarx/vite-plugin/hmr-client'));
17
- program.body.unshift(importDecl);
18
- }
19
- /**
20
- * 注入 getComponentView 导入
21
- * 使用唯一的别名避免与用户代码冲突
22
- * @param program - AST Program 节点
23
- */
24
- function injectGetComponentViewImport(program) {
25
- // 创建独立的 import 语句,使用不会冲突的别名
26
- const importDecl = t.importDeclaration([t.importSpecifier(t.identifier(GET_COMPONENT_VIEW_ALIAS), t.identifier('getComponentView'))], t.stringLiteral('vitarx'));
27
- program.body.unshift(importDecl);
28
- }
29
- /**
30
- * 创建组件函数体内的 HMR 注册代码
31
- * @param variableNames - 需要追踪的变量名列表
32
- * @returns HMR 注册语句数组
33
- */
34
- function createHMRRegistrationStatements(variableNames) {
35
- const statements = [];
36
- // 声明并获取当前视图实例
37
- statements.push(t.variableDeclaration('const', [
38
- t.variableDeclarator(t.identifier(HMR.view), t.callExpression(t.identifier(GET_COMPONENT_VIEW_ALIAS), []))
39
- ]));
40
- // 注册到 HMR 管理器
41
- statements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.identifier(HMR.manager), t.identifier('instance')), t.identifier('register')), [t.identifier(HMR.view)])));
42
- // 创建状态追踪对象
43
- const stateProperties = variableNames.map(name => t.objectMethod('get', t.identifier(name), [], t.blockStatement([t.returnStatement(t.identifier(name))])));
44
- // 异步设置状态
45
- statements.push(t.expressionStatement(t.logicalExpression('&&', t.identifier(HMR.view), t.callExpression(t.memberExpression(t.callExpression(t.memberExpression(t.identifier('Promise'), t.identifier('resolve')), []), t.identifier('then')), [
46
- t.arrowFunctionExpression([], t.blockStatement([
47
- t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.identifier(HMR.view), t.identifier(HMR.state)), t.objectExpression(stateProperties)))
48
- ]))
49
- ]))));
50
- return statements;
51
- }
52
- /**
53
- * 从函数体中收集局部变量名
54
- * @param functionBody - 函数体语句块
55
- * @returns 变量名数组
56
- */
57
- function collectLocalVariableNames(functionBody) {
58
- const variableNames = new Set();
59
- for (const stmt of functionBody.body) {
60
- if (stmt.type === 'VariableDeclaration') {
61
- for (const decl of stmt.declarations) {
62
- if (decl.id.type !== 'VoidPattern') {
63
- collectPatternBindings(decl.id, variableNames);
64
- }
65
- }
66
- }
67
- }
68
- return Array.from(variableNames);
69
- }
70
- /**
71
- * 判断表达式是否为函数类型
72
- * 包括:箭头函数、函数表达式、类表达式
73
- */
74
- function isFunctionExpression(expr) {
75
- if (!expr)
76
- return false;
77
- return (expr.type === 'ArrowFunctionExpression' ||
78
- expr.type === 'FunctionExpression' ||
79
- expr.type === 'ClassExpression');
80
- }
81
- /**
82
- * 创建状态恢复表达式
83
- * 格式:__$VITARX_HMR$__.instance.memo(__$VITARX_HMR_VIEW_NODE$__, '变量名') ?? 原始初始值
84
- */
85
- function createMemoExpression(variableName, originalInit) {
86
- return t.logicalExpression('??', t.callExpression(t.memberExpression(t.memberExpression(t.identifier(HMR.manager), t.identifier('instance')), t.identifier('memo')), [t.identifier(HMR.view), t.stringLiteral(variableName)]), originalInit);
87
- }
88
- /**
89
- * 为单个变量声明注入状态恢复代码
90
- * 仅处理标识符类型的变量声明,且初始值不是函数
91
- */
92
- function injectStatePreservationForDeclaration(decl) {
93
- // 只处理标识符类型的变量声明
94
- if (decl.id.type !== 'Identifier')
95
- return;
96
- // 没有初始值,不需要处理
97
- if (!decl.init)
98
- return;
99
- // 初始值是函数,不需要状态恢复
100
- if (isFunctionExpression(decl.init))
101
- return;
102
- // 注入状态恢复代码
103
- decl.init = createMemoExpression(decl.id.name, decl.init);
104
- }
105
- /**
106
- * 为函数体内的变量声明注入状态恢复代码
107
- */
108
- function injectStatePreservation(functionBody) {
109
- for (const stmt of functionBody.body) {
110
- if (stmt.type === 'VariableDeclaration') {
111
- for (const decl of stmt.declarations) {
112
- injectStatePreservationForDeclaration(decl);
113
- }
114
- }
115
- }
116
- }
8
+ import { injectHMRImport, injectGetComponentViewImport } from './inject-imports.js';
9
+ import { createHMRRegistrationStatements, createWrappedComponentHMRStatements, collectLocalVariableNames, injectStatePreservation } from './inject-state.js';
117
10
  /**
118
11
  * 为组件函数注入 HMR 注册代码
119
12
  * @param func - 函数声明/表达式/箭头函数
120
13
  * @param variableNames - 需要追踪的变量名列表
14
+ * @param isWrapped - 是否为包装组件
15
+ * @param componentName - 组件名称(包装组件需要)
121
16
  */
122
- function injectHMRIntoFunction(func, variableNames) {
123
- // 处理箭头函数没有函数体的情况(表达式体)
17
+ function injectHMRIntoFunction(func, variableNames, isWrapped = false, componentName) {
124
18
  if (func.type === 'ArrowFunctionExpression' && func.body.type !== 'BlockStatement') {
125
- // 将表达式体转换为块语句
126
19
  const returnStmt = t.returnStatement(func.body);
127
20
  func.body = t.blockStatement([returnStmt]);
128
21
  }
129
22
  if (!func.body || func.body.type !== 'BlockStatement')
130
23
  return;
131
- // 注入状态恢复代码
132
- injectStatePreservation(func.body);
133
- // 注入 HMR 注册代码
134
- const statements = createHMRRegistrationStatements(variableNames);
24
+ if (!isWrapped) {
25
+ injectStatePreservation(func.body);
26
+ }
27
+ const statements = isWrapped
28
+ ? createWrappedComponentHMRStatements(componentName)
29
+ : createHMRRegistrationStatements(variableNames);
135
30
  func.body.body.unshift(...statements);
136
31
  }
137
32
  /**
@@ -171,19 +66,14 @@ function generateComponentId(filename, componentName) {
171
66
  export function injectHMRSupport(program, components, filename) {
172
67
  if (components.length === 0)
173
68
  return;
174
- // 注入必要的导入
175
69
  injectHMRImport(program);
176
70
  injectGetComponentViewImport(program);
177
- // 为每个组件函数注入 HMR 代码
178
- for (const { node } of components) {
179
- // 收集局部变量名(如果有函数体)
71
+ for (const { node, isWrapped, name } of components) {
180
72
  const variableNames = node.body?.type === 'BlockStatement' ? collectLocalVariableNames(node.body) : [];
181
- injectHMRIntoFunction(node, variableNames);
73
+ injectHMRIntoFunction(node, variableNames, isWrapped, name);
182
74
  }
183
- // 为每个组件绑定 ID
184
75
  for (const { name } of components) {
185
76
  program.body.push(createBindIdStatement(name, generateComponentId(filename, name)));
186
77
  }
187
- // 注入 import.meta.hot.accept
188
78
  program.body.push(createHotAcceptStatement());
189
79
  }
@@ -13,8 +13,8 @@ const API_IMPORT_CONFIG = [
13
13
  { name: 'createView', importKey: 'createView' },
14
14
  { name: 'Fragment', importKey: 'Fragment' },
15
15
  { name: 'branch', importKey: 'branch' },
16
- { name: 'dynamic', importKey: 'dynamic' },
17
- { name: 'access', importKey: 'access' },
16
+ { name: 'expr', importKey: 'expr' },
17
+ { name: 'accessor', importKey: 'accessor' },
18
18
  { name: 'withDirectives', importKey: 'withDirectives' },
19
19
  { name: 'unref', importKey: 'unref' },
20
20
  { name: 'isRef', importKey: 'isRef' }
@@ -4,25 +4,28 @@
4
4
  * @module passes/jsx/processChildren
5
5
  */
6
6
  import * as t from '@babel/types';
7
- import { isBooleanLiteral, isConditionalExpression, isIdentifier, isJSXElement, isJSXExpressionContainer, isJSXFragment, isJSXText, isLogicalExpression, isMemberExpression, isNumericLiteral, isStringLiteral } from '@babel/types';
7
+ import { isBinaryExpression, isConditionalExpression, isIdentifier, isJSXElement, isJSXExpressionContainer, isJSXFragment, isJSXText, isLogicalExpression, isMemberExpression } from '@babel/types';
8
8
  import { markImport } from '../../context.js';
9
- import { addPureComment, createAccessCall, createBinaryBranch, createDynamicCall, getAlias, getDevLocInfo } from '../../utils/index.js';
9
+ import { addPureComment, createAccessorCall, createBinaryBranch, createExprCall, getAlias } from '../../utils/index.js';
10
10
  /**
11
- * 处理成员表达式
11
+ * 处理成员表达式,生成 accessor 调用
12
12
  */
13
13
  function handleMemberExpression(expr, ctx) {
14
- markImport(ctx, 'access');
15
- const accessAlias = getAlias(ctx.vitarxAliases, 'access');
16
- return createAccessCall(expr.object, expr.property, accessAlias);
14
+ markImport(ctx, 'accessor');
15
+ const accessorAlias = getAlias(ctx.vitarxAliases, 'accessor');
16
+ return createAccessorCall(expr.object, expr.property, accessorAlias);
17
17
  }
18
18
  /**
19
- * 处理逻辑表达式
19
+ * 使用 expr 包装表达式
20
+ * 用于逻辑表达式、二元表达式和调用表达式的统一包装
21
+ * 运行时根据返回值类型决定是否跟踪响应式:
22
+ * - 数组返回值:原样返回(仅渲染一次)
23
+ * - 其他返回值:创建 DynamicView 追踪
20
24
  */
21
- function handleLogicalExpression(expr, ctx, loc) {
22
- markImport(ctx, 'dynamic');
23
- const dynamicAlias = getAlias(ctx.vitarxAliases, 'dynamic');
24
- const locInfo = loc ? getDevLocInfo(ctx, { loc }) : null;
25
- return addPureComment(createDynamicCall(expr, dynamicAlias, locInfo));
25
+ function wrapWithExpr(expr, ctx) {
26
+ markImport(ctx, 'expr');
27
+ const exprAlias = getAlias(ctx.vitarxAliases, 'expr');
28
+ return addPureComment(createExprCall(expr, exprAlias), ctx);
26
29
  }
27
30
  /**
28
31
  * 处理子节点数组
@@ -42,59 +45,40 @@ export function processChildren(children, ctx) {
42
45
  }
43
46
  /**
44
47
  * 处理单个子节点
48
+ * JSX 容器节点在此拆包后委托给 processChildExpression 处理
49
+ * 已转换的 API 调用(createView/branch 等 CallExpression)直接透传
45
50
  */
46
51
  function processChildNode(node, ctx) {
47
- // JSX 文本
48
52
  if (isJSXText(node)) {
49
53
  const trimmed = node.value.trim();
50
54
  if (!trimmed)
51
55
  return null;
52
56
  return t.stringLiteral(trimmed);
53
57
  }
54
- // JSX 表达式容器
55
58
  if (isJSXExpressionContainer(node)) {
56
59
  if (node.expression.type === 'JSXEmptyExpression')
57
60
  return null;
58
- return processChildExpression(node.expression, ctx, node.loc);
61
+ return processChildExpression(node.expression, ctx);
59
62
  }
60
- // JSX 展开子元素
61
63
  if (node.type === 'JSXSpreadChild') {
62
- return processChildExpression(node.expression, ctx, node.loc);
64
+ return processChildExpression(node.expression, ctx);
63
65
  }
64
- // JSX 元素或片段
65
66
  if (isJSXElement(node) || isJSXFragment(node)) {
66
67
  return node;
67
68
  }
68
- // 字面量
69
- if (isStringLiteral(node) || isNumericLiteral(node) || isBooleanLiteral(node)) {
70
- return node;
71
- }
72
- // 标识符
73
- if (isIdentifier(node)) {
74
- return node;
75
- }
76
- // 成员表达式
77
- if (isMemberExpression(node)) {
78
- return handleMemberExpression(node, ctx);
79
- }
80
- // 条件表达式
81
- if (isConditionalExpression(node)) {
82
- return processConditionalExpression(node, ctx);
83
- }
84
- // 逻辑表达式
85
- if (isLogicalExpression(node)) {
86
- return handleLogicalExpression(node, ctx);
87
- }
88
- // 调用表达式
69
+ // 已转换的 API 调用(createView/branch 等)直接透传,不包装 expr
89
70
  if (node.type === 'CallExpression') {
90
71
  return node;
91
72
  }
92
- return node;
73
+ // 其他表达式类型委托给 processChildExpression
74
+ return processChildExpression(node, ctx);
93
75
  }
94
76
  /**
95
- * 处理子表达式
77
+ * 处理子表达式(来自 JSX 表达式容器或条件分支)
78
+ * 根据表达式类型生成对应的运行时 API 调用
79
+ * CallExpression 在此用 expr 包装(用户函数调用需要响应式追踪)
96
80
  */
97
- function processChildExpression(expr, ctx, loc) {
81
+ function processChildExpression(expr, ctx) {
98
82
  if (isIdentifier(expr)) {
99
83
  return expr;
100
84
  }
@@ -104,22 +88,17 @@ function processChildExpression(expr, ctx, loc) {
104
88
  if (isConditionalExpression(expr)) {
105
89
  return processConditionalExpression(expr, ctx);
106
90
  }
107
- if (isLogicalExpression(expr)) {
108
- return handleLogicalExpression(expr, ctx, loc);
91
+ if (isLogicalExpression(expr) || isBinaryExpression(expr) || expr.type === 'CallExpression') {
92
+ return wrapWithExpr(expr, ctx);
109
93
  }
110
94
  return expr;
111
95
  }
112
96
  /**
113
- * 处理条件表达式
114
- * 转换为 branch 调用
97
+ * 处理条件表达式,转换为 branch 调用
115
98
  */
116
99
  function processConditionalExpression(node, ctx) {
117
100
  const { test, consequent, alternate } = node;
118
- // 处理分支
119
101
  const processedConsequent = processChildNode(consequent, ctx) || t.nullLiteral();
120
102
  const processedAlternate = processChildNode(alternate, ctx) || t.nullLiteral();
121
- // 获取位置信息(仅开发环境)
122
- const locInfo = getDevLocInfo(ctx, node);
123
- // 使用公共的 createBinaryBranch
124
- return createBinaryBranch(test, processedConsequent, processedAlternate, ctx, locInfo);
103
+ return createBinaryBranch(test, processedConsequent, processedAlternate, ctx);
125
104
  }
@@ -2,7 +2,7 @@ import * as t from '@babel/types';
2
2
  import { isJSXElement } from '@babel/types';
3
3
  import { addWarning, markImport } from '../../context.js';
4
4
  import { createError, createWarning } from '../../error.js';
5
- import { addPureComment, createArrowFunction, createBranch, createCreateViewCall, getAlias, getDevLocInfo, getDirectiveValue, getJSXAttributeByName, getJSXElementName, hasEffectiveChildren, filterEffectiveChildren, isNativeElement, isVElse, isVIf, isVIfChain, removeVIfChainDirectives } from '../../utils/index.js';
5
+ import { addPureComment, createArrowFunction, createBranch, createCreateViewCall, filterEffectiveChildren, getAlias, getDevLocInfo, getDirectiveValue, getJSXAttributeByName, getJSXElementName, hasEffectiveChildren, isNativeElement, isVElse, isVIf, isVIfChain, removeVIfChainDirectives } from '../../utils/index.js';
6
6
  import { processDirectives } from '../directives/index.js';
7
7
  import { processProps } from '../props/index.js';
8
8
  import { processChildren } from './processChildren.js';
@@ -87,7 +87,7 @@ export function transformJSXElement(node, ctx, handleVIf = false) {
87
87
  viewCall = processDirectives(viewCall, directives, ctx);
88
88
  }
89
89
  else {
90
- viewCall = addPureComment(viewCall);
90
+ viewCall = addPureComment(viewCall, ctx);
91
91
  }
92
92
  if (node.loc) {
93
93
  viewCall.loc = node.loc;
@@ -146,10 +146,7 @@ function transformSingleVIf(node, ctx) {
146
146
  const transformedNode = transformJSXElement(node, ctx, false);
147
147
  if (!transformedNode)
148
148
  return null;
149
- // 获取位置信息(仅开发环境)
150
- const locInfo = getDevLocInfo(ctx, node);
151
- // 生成 branch 调用
152
- const branchCall = createBranch({ conditions: [condition], branches: [createArrowFunction(transformedNode)], locInfo }, ctx);
149
+ const branchCall = createBranch({ conditions: [condition], branches: [createArrowFunction(transformedNode)] }, ctx);
153
150
  if (node.loc) {
154
151
  branchCall.loc = node.loc;
155
152
  }
@@ -1,5 +1,5 @@
1
1
  import * as t from '@babel/types';
2
- import { addPureComment, createCreateViewCall, filterWhitespaceChildren, getAlias, getDevLocInfo, validateMatchInSwitch } from '../../utils/index.js';
2
+ import { addPureComment, createCreateViewCall, filterWhitespaceChildren, getAlias, getDevLocInfo, validateNoDirectMatchChild } from '../../utils/index.js';
3
3
  import { processChildren } from './processChildren.js';
4
4
  /**
5
5
  * 处理 JSX Fragment
@@ -11,7 +11,7 @@ export function processJSXFragment(path, ctx) {
11
11
  // 过滤空白子节点
12
12
  const children = filterWhitespaceChildren(node.children);
13
13
  // 校验 Match 组件
14
- validateMatchInSwitch(children);
14
+ validateNoDirectMatchChild(children);
15
15
  // 标记需要的导入
16
16
  ctx.imports.Fragment = true;
17
17
  ctx.imports.createView = true;
@@ -20,7 +20,7 @@ export function processJSXFragment(path, ctx) {
20
20
  const locInfo = getDevLocInfo(ctx, node);
21
21
  // 无子元素
22
22
  if (children.length === 0) {
23
- const viewCall = addPureComment(createCreateViewCall(t.identifier(fragmentAlias), null, locInfo, createViewAlias));
23
+ const viewCall = addPureComment(createCreateViewCall(t.identifier(fragmentAlias), null, locInfo, createViewAlias), ctx);
24
24
  if (node.loc)
25
25
  viewCall.loc = node.loc;
26
26
  path.replaceWith(viewCall);
@@ -30,7 +30,7 @@ export function processJSXFragment(path, ctx) {
30
30
  const processedChildren = processChildren(children, ctx);
31
31
  const childrenValue = processedChildren.length === 1 ? processedChildren[0] : t.arrayExpression(processedChildren);
32
32
  const props = t.objectExpression([t.objectProperty(t.identifier('children'), childrenValue)]);
33
- const viewCall = addPureComment(createCreateViewCall(t.identifier(fragmentAlias), props, locInfo, createViewAlias));
33
+ const viewCall = addPureComment(createCreateViewCall(t.identifier(fragmentAlias), props, locInfo, createViewAlias), ctx);
34
34
  if (node.loc)
35
35
  viewCall.loc = node.loc;
36
36
  path.replaceWith(viewCall);
@@ -5,16 +5,9 @@
5
5
  */
6
6
  import * as t from '@babel/types';
7
7
  import { createError } from '../../error.js';
8
- import { isNativeElement } from '../../utils/index.js';
8
+ import { getJSXElementName, isNativeElement } from '../../utils/index.js';
9
9
  import { createProperty, getAttributeValue, processAttribute, processSpreadAttribute } from './attribute.js';
10
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
11
  /**
19
12
  * 校验 class 和 className 不能同时存在
20
13
  */
@@ -4,16 +4,13 @@
4
4
  * @module transform
5
5
  */
6
6
  import { type GeneratorResult } from '@babel/generator';
7
+ import type { CompileOptions } from './types.js';
7
8
  export interface TransformResult extends GeneratorResult {
8
9
  }
9
- export interface CompileOptions {
10
- hmr: boolean;
11
- dev: boolean;
12
- ssr: boolean;
13
- runtimeModule: string;
14
- sourceMap: boolean | 'inline' | 'both';
15
- transformClassNameToClass: boolean;
16
- }
10
+ /**
11
+ * 检查文件是否需要转换
12
+ */
13
+ export declare function shouldTransform(id: string): boolean;
17
14
  /**
18
15
  * 转换 JSX/TSX 代码
19
16
  */
package/dist/transform.js CHANGED
@@ -9,15 +9,6 @@ import traverse from '@babel/traverse';
9
9
  import { createContext } from './context.js';
10
10
  import { collectExistingImports, collectLocalBindings, collectRefApiAliases, collectRefVariables, injectHMRSupport, injectImports, processJSXElement, processJSXFragment, processPureCompileComponent, processVIfChain, transformJSXElement } from './passes/index.js';
11
11
  import { collectComponentFunctions, generateUniqueAlias, getJSXElementName, isPureCompileComponent } from './utils/index.js';
12
- /** 用于追踪已处理的节点 */
13
- const processedNodes = new WeakSet();
14
- /**
15
- * 检查文件是否需要转换
16
- */
17
- function shouldTransform(id) {
18
- const ext = id.split('?')[0].split('.').pop()?.toLowerCase();
19
- return ext === 'jsx' || ext === 'tsx';
20
- }
21
12
  /**
22
13
  * 创建解析器选项
23
14
  */
@@ -49,8 +40,8 @@ function setupAliases(ctx, program) {
49
40
  'createView',
50
41
  'Fragment',
51
42
  'branch',
52
- 'dynamic',
53
- 'access',
43
+ 'expr',
44
+ 'accessor',
54
45
  'withDirectives',
55
46
  'unref',
56
47
  'isRef'
@@ -66,6 +57,9 @@ function setupAliases(ctx, program) {
66
57
  if (ctx.options.hmr) {
67
58
  ctx.vitarxAliases.createView = generateUniqueAlias('jsxDEV', allNames);
68
59
  }
60
+ if (vitarxImports.has('builder')) {
61
+ ctx.builderAlias = vitarxImports.get('builder');
62
+ }
69
63
  }
70
64
  /**
71
65
  * 收集 ref 相关信息
@@ -83,21 +77,21 @@ function transformAST(ast, ctx) {
83
77
  babelTraverse(ast, {
84
78
  JSXElement: {
85
79
  enter(path) {
86
- if (processedNodes.has(path.node))
80
+ if (ctx.processedNodes.has(path.node))
87
81
  return;
88
82
  const name = getJSXElementName(path.node);
89
83
  if (name && isPureCompileComponent(name)) {
90
- processedNodes.add(path.node);
84
+ ctx.processedNodes.add(path.node);
91
85
  processPureCompileComponent(path, ctx);
92
86
  }
93
87
  },
94
88
  exit(path) {
95
- if (processedNodes.has(path.node))
89
+ if (ctx.processedNodes.has(path.node))
96
90
  return;
97
91
  const name = getJSXElementName(path.node);
98
92
  if (name && isPureCompileComponent(name))
99
93
  return;
100
- processedNodes.add(path.node);
94
+ ctx.processedNodes.add(path.node);
101
95
  processJSXElement(path, ctx);
102
96
  }
103
97
  },
@@ -106,9 +100,9 @@ function transformAST(ast, ctx) {
106
100
  processVIfChain(path, ctx, transformJSXElement);
107
101
  },
108
102
  exit(path) {
109
- if (processedNodes.has(path.node))
103
+ if (ctx.processedNodes.has(path.node))
110
104
  return;
111
- processedNodes.add(path.node);
105
+ ctx.processedNodes.add(path.node);
112
106
  processJSXFragment(path, ctx);
113
107
  }
114
108
  }
@@ -122,17 +116,22 @@ function generateCode(ast, code, id, sourceMap) {
122
116
  const output = babelGenerate(ast, { sourceMaps: !!sourceMap, filename: id, sourceFileName: id }, code);
123
117
  return { code: output.code, map: output.map };
124
118
  }
119
+ /**
120
+ * 检查文件是否需要转换
121
+ */
122
+ export function shouldTransform(id) {
123
+ const ext = id.split('?')[0].split('.').pop()?.toLowerCase();
124
+ return ext === 'jsx' || ext === 'tsx';
125
+ }
125
126
  /**
126
127
  * 转换 JSX/TSX 代码
127
128
  */
128
129
  export async function transform(code, id, options) {
129
- if (!shouldTransform(id))
130
- return null;
131
130
  const ast = parse(code, createParserOptions());
132
131
  const ctx = createContext(code, id, options, ast);
133
132
  setupAliases(ctx, ast.program);
134
133
  collectRefInfo(ctx, ast.program);
135
- const components = collectComponentFunctions(ast.program);
134
+ const components = collectComponentFunctions(ast.program, ctx.builderAlias);
136
135
  transformAST(ast, ctx);
137
136
  injectImports(ast.program, ctx);
138
137
  if (options.hmr && components.length > 0) {
package/dist/types.d.ts CHANGED
@@ -1,4 +1,15 @@
1
1
  import type { RenderUnit, View } from 'vitarx';
2
+ /**
3
+ * 编译选项
4
+ */
5
+ export interface CompileOptions {
6
+ hmr: boolean;
7
+ dev: boolean;
8
+ ssr: boolean;
9
+ runtimeModule: string;
10
+ sourceMap: boolean | 'inline' | 'both';
11
+ transformClassNameToClass: boolean;
12
+ }
2
13
  export interface IfBlockProps {
3
14
  /**
4
15
  * 子元素列表
@@ -3,7 +3,8 @@
3
3
  * @module utils/ast-builders
4
4
  */
5
5
  import * as t from '@babel/types';
6
- import { type ArrowFunctionExpression, type CallExpression, type Expression, type ObjectExpression, type SourceLocation } from '@babel/types';
6
+ import { type ArrowFunctionExpression, type CallExpression, type Expression, type ObjectExpression } from '@babel/types';
7
+ import type { SourceLocation } from 'acorn';
7
8
  import type { TransformContext, VitarxImportAliases } from '../context.js';
8
9
  /**
9
10
  * 创建 unref 调用
@@ -13,30 +14,28 @@ import type { TransformContext, VitarxImportAliases } from '../context.js';
13
14
  */
14
15
  export declare function createUnrefCall(argument: Expression, alias?: string): CallExpression;
15
16
  /**
16
- * 创建 access 调用
17
+ * 创建 accessor 调用
17
18
  * @param object - 对象表达式
18
19
  * @param key - 键表达式
19
- * @param alias - access 别名
20
+ * @param alias - accessor 别名
20
21
  * @returns CallExpression
21
22
  */
22
- export declare function createAccessCall(object: Expression, key: Expression, alias?: string): CallExpression;
23
+ export declare function createAccessorCall(object: Expression, key: Expression, alias?: string): CallExpression;
23
24
  /**
24
- * 创建 dynamic 调用
25
+ * 创建 expr 调用
25
26
  * @param argument - 参数表达式
26
- * @param alias - dynamic 别名
27
- * @param locInfo - 位置信息对象
27
+ * @param alias - expr 别名
28
28
  * @returns CallExpression
29
29
  */
30
- export declare function createDynamicCall(argument: Expression, alias?: string, locInfo?: ObjectExpression | null): CallExpression;
30
+ export declare function createExprCall(argument: Expression, alias?: string): CallExpression;
31
31
  /**
32
32
  * 创建 branch 调用
33
33
  * @param condition - 条件函数
34
34
  * @param branches - 分支函数数组
35
35
  * @param alias - branch 别名
36
- * @param locInfo - 位置信息对象
37
36
  * @returns CallExpression
38
37
  */
39
- export declare function createBranchCall(condition: ArrowFunctionExpression, branches: ArrowFunctionExpression[], alias?: string, locInfo?: ObjectExpression | null): CallExpression;
38
+ export declare function createBranchCall(condition: ArrowFunctionExpression, branches: ArrowFunctionExpression[], alias?: string): CallExpression;
40
39
  /**
41
40
  * 创建 createView 调用
42
41
  * @param type - 元素类型
@@ -60,19 +59,13 @@ export declare function createWithDirectivesCall(view: Expression, directives: A
60
59
  * @returns ArrowFunctionExpression
61
60
  */
62
61
  export declare function createArrowFunction(body: Expression): ArrowFunctionExpression;
63
- /**
64
- * 创建位置信息对象
65
- * @param filename - 文件名
66
- * @param loc - 源码位置
67
- * @returns ObjectExpression
68
- */
69
- export declare function createLocationObject(filename: string, loc: SourceLocation): ObjectExpression;
70
62
  /**
71
63
  * 为调用表达式添加 @__PURE__ 注释
72
64
  * @param node - 调用表达式节点
65
+ * @param ctx - 转换上下文
73
66
  * @returns 添加注释后的节点
74
67
  */
75
- export declare function addPureComment<T extends CallExpression>(node: T): T;
68
+ export declare function addPureComment<T extends CallExpression>(node: T, ctx: TransformContext): T;
76
69
  /**
77
70
  * 获取 API 别名
78
71
  * @param aliases - 别名映射
@@ -80,6 +73,13 @@ export declare function addPureComment<T extends CallExpression>(node: T): T;
80
73
  * @returns 别名或原名
81
74
  */
82
75
  export declare function getAlias(aliases: VitarxImportAliases, name: keyof VitarxImportAliases): string;
76
+ /**
77
+ * 创建位置信息对象
78
+ * @param filename - 文件名
79
+ * @param loc - 源码位置
80
+ * @returns ObjectExpression
81
+ */
82
+ export declare function createLocationObject(filename: string, loc: SourceLocation): ObjectExpression;
83
83
  /**
84
84
  * 获取开发环境下的位置信息对象
85
85
  * 仅在开发环境下返回位置信息,生产环境返回 null