@vitarx/plugin-vite 1.0.1 → 1.0.2-alpha.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.
- package/dist/hmr-client/index.d.ts +15 -5
- package/dist/hmr-client/index.js +47 -25
- package/dist/passes/hmr/inject-imports.d.ts +4 -1
- package/dist/passes/hmr/inject-imports.js +8 -1
- package/dist/passes/hmr/inject-state.d.ts +6 -1
- package/dist/passes/hmr/inject-state.js +58 -5
- package/dist/passes/hmr/inject.d.ts +1 -1
- package/dist/passes/hmr/inject.js +27 -2
- package/dist/passes/imports/collectImports.d.ts +4 -4
- package/dist/passes/imports/collectImports.js +20 -5
- package/dist/passes/imports/collectRefVariables.d.ts +2 -2
- package/dist/passes/imports/collectRefVariables.js +47 -3
- package/dist/passes/imports/injectImports.d.ts +1 -0
- package/dist/passes/imports/injectImports.js +28 -2
- package/dist/transform.js +11 -1
- package/dist/utils/ast-builders.d.ts +49 -41
- package/dist/utils/ast-builders.js +60 -41
- package/dist/utils/ast-guards.d.ts +2 -1
- package/dist/utils/ast-guards.js +4 -1
- package/dist/utils/collect-names.d.ts +13 -4
- package/dist/utils/collect-names.js +38 -4
- package/dist/utils/component-collect.d.ts +4 -2
- package/dist/utils/component-collect.js +181 -6
- package/dist/utils/generate.d.ts +3 -0
- package/dist/utils/generate.js +4 -0
- package/dist/utils/jsx-helpers.d.ts +14 -0
- package/dist/utils/jsx-helpers.js +21 -0
- package/dist/utils/pattern-helpers.d.ts +4 -4
- package/dist/utils/pattern-helpers.js +13 -4
- package/dist/utils/vif-helpers.d.ts +8 -0
- package/dist/utils/vif-helpers.js +36 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JSX 相关工具函数
|
|
3
|
+
* 提供 JSX 元素的各种操作和判断方法
|
|
3
4
|
* @module utils/jsx-helpers
|
|
4
5
|
*/
|
|
5
6
|
import * as t from '@babel/types';
|
|
@@ -9,22 +10,30 @@ import { createError } from '../error.js';
|
|
|
9
10
|
import { isWhitespaceJSXText } from './ast-guards.js';
|
|
10
11
|
/**
|
|
11
12
|
* 获取 JSX 元素的名称
|
|
13
|
+
* @param node - JSX 元素节点
|
|
14
|
+
* @returns 元素名称(Identifier)或 null(MemberExpression)
|
|
12
15
|
*/
|
|
13
16
|
export function getJSXElementName(node) {
|
|
14
17
|
const nameNode = node.openingElement.name;
|
|
18
|
+
// 只处理简单标识符,MemberExpression 返回 null
|
|
15
19
|
return nameNode.type === 'JSXIdentifier' ? nameNode.name : null;
|
|
16
20
|
}
|
|
17
21
|
/**
|
|
18
22
|
* 将 JSX 元素名称节点转换为 createView 的类型表达式
|
|
19
23
|
* JSXIdentifier → Identifier(组件)或 StringLiteral(原生元素)
|
|
20
24
|
* JSXMemberExpression → MemberExpression(如 Obj.Key → Obj.Key)
|
|
25
|
+
* @param node - JSX 元素节点
|
|
26
|
+
* @returns 类型表达式或 null
|
|
21
27
|
*/
|
|
22
28
|
export function resolveJSXElementType(node) {
|
|
23
29
|
const nameNode = node.openingElement.name;
|
|
30
|
+
// 处理简单标识符(如 <div> 或 <Component>)
|
|
24
31
|
if (nameNode.type === 'JSXIdentifier') {
|
|
25
32
|
const name = nameNode.name;
|
|
33
|
+
// 原生元素转为字符串,组件转为标识符
|
|
26
34
|
return isNativeElement(name) ? t.stringLiteral(name) : t.identifier(name);
|
|
27
35
|
}
|
|
36
|
+
// 处理成员表达式(如 <Obj.Key>)
|
|
28
37
|
if (nameNode.type === 'JSXMemberExpression') {
|
|
29
38
|
return jsxMemberExprToMemberExpr(nameNode);
|
|
30
39
|
}
|
|
@@ -33,8 +42,11 @@ export function resolveJSXElementType(node) {
|
|
|
33
42
|
/**
|
|
34
43
|
* 递归转换 JSXMemberExpression 为 MemberExpression
|
|
35
44
|
* Obj.Key → Obj.Key, A.B.C → A.B.C
|
|
45
|
+
* @param node - JSXMemberExpression 节点
|
|
46
|
+
* @returns MemberExpression 节点
|
|
36
47
|
*/
|
|
37
48
|
function jsxMemberExprToMemberExpr(node) {
|
|
49
|
+
// 递归处理对象部分
|
|
38
50
|
const object = node.object.type === 'JSXMemberExpression'
|
|
39
51
|
? jsxMemberExprToMemberExpr(node.object)
|
|
40
52
|
: t.identifier(node.object.name);
|
|
@@ -42,18 +54,27 @@ function jsxMemberExprToMemberExpr(node) {
|
|
|
42
54
|
}
|
|
43
55
|
/**
|
|
44
56
|
* 判断名称是否为纯编译组件
|
|
57
|
+
* 纯编译组件在编译时完全展开,不会生成运行时调用
|
|
58
|
+
* @param name - 元素名称
|
|
59
|
+
* @returns 是否为纯编译组件
|
|
45
60
|
*/
|
|
46
61
|
export function isPureCompileComponent(name) {
|
|
47
62
|
return PURE_COMPILE_COMPONENTS.includes(name);
|
|
48
63
|
}
|
|
49
64
|
/**
|
|
50
65
|
* 判断名称是否为组件(首字母大写)
|
|
66
|
+
* 遵循 React/Vue 的组件命名约定
|
|
67
|
+
* @param name - 元素名称
|
|
68
|
+
* @returns 是否为组件
|
|
51
69
|
*/
|
|
52
70
|
export function isComponent(name) {
|
|
53
71
|
return name.length > 0 && name[0] === name[0].toUpperCase();
|
|
54
72
|
}
|
|
55
73
|
/**
|
|
56
74
|
* 判断名称是否为原生元素
|
|
75
|
+
* 原生元素使用小写字母开头
|
|
76
|
+
* @param name - 元素名称
|
|
77
|
+
* @returns 是否为原生元素
|
|
57
78
|
*/
|
|
58
79
|
export function isNativeElement(name) {
|
|
59
80
|
return !isComponent(name);
|
|
@@ -7,14 +7,14 @@ import type { LVal, ObjectPattern } from '@babel/types';
|
|
|
7
7
|
/**
|
|
8
8
|
* 从绑定模式中收集变量名
|
|
9
9
|
* 支持标识符、对象模式、数组模式
|
|
10
|
-
* @param pattern -
|
|
11
|
-
* @param variables -
|
|
10
|
+
* @param pattern - 绑定模式节点
|
|
11
|
+
* @param variables - 存储变量名的集合
|
|
12
12
|
*/
|
|
13
13
|
export declare function collectPatternBindings(pattern: LVal, variables: Set<string>): void;
|
|
14
14
|
/**
|
|
15
15
|
* 从对象解构模式中收集变量名
|
|
16
16
|
* 专门用于 toRefs 解构场景
|
|
17
|
-
* @param pattern -
|
|
18
|
-
* @param variables -
|
|
17
|
+
* @param pattern - 对象模式节点
|
|
18
|
+
* @param variables - 存储变量名的集合
|
|
19
19
|
*/
|
|
20
20
|
export declare function collectObjectPatternBindings(pattern: ObjectPattern, variables: Set<string>): void;
|
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 从绑定模式中收集变量名
|
|
3
3
|
* 支持标识符、对象模式、数组模式
|
|
4
|
-
* @param pattern -
|
|
5
|
-
* @param variables -
|
|
4
|
+
* @param pattern - 绑定模式节点
|
|
5
|
+
* @param variables - 存储变量名的集合
|
|
6
6
|
*/
|
|
7
7
|
export function collectPatternBindings(pattern, variables) {
|
|
8
|
+
// 处理简单标识符
|
|
8
9
|
if (pattern.type === 'Identifier') {
|
|
9
10
|
variables.add(pattern.name);
|
|
10
11
|
}
|
|
11
12
|
else if (pattern.type === 'ObjectPattern') {
|
|
13
|
+
// 处理对象解构模式
|
|
12
14
|
for (const prop of pattern.properties) {
|
|
13
15
|
if (prop.type === 'RestElement') {
|
|
16
|
+
// 处理剩余运算符(...rest)
|
|
14
17
|
collectPatternBindings(prop.argument, variables);
|
|
15
18
|
}
|
|
16
19
|
else {
|
|
20
|
+
// 处理普通属性,递归收集 value
|
|
17
21
|
collectPatternBindings(prop.value, variables);
|
|
18
22
|
}
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
25
|
else if (pattern.type === 'ArrayPattern') {
|
|
26
|
+
// 处理数组解构模式
|
|
22
27
|
for (const elem of pattern.elements) {
|
|
23
28
|
if (elem) {
|
|
29
|
+
// 递归处理每个非空元素
|
|
24
30
|
collectPatternBindings(elem, variables);
|
|
25
31
|
}
|
|
26
32
|
}
|
|
@@ -29,18 +35,21 @@ export function collectPatternBindings(pattern, variables) {
|
|
|
29
35
|
/**
|
|
30
36
|
* 从对象解构模式中收集变量名
|
|
31
37
|
* 专门用于 toRefs 解构场景
|
|
32
|
-
* @param pattern -
|
|
33
|
-
* @param variables -
|
|
38
|
+
* @param pattern - 对象模式节点
|
|
39
|
+
* @param variables - 存储变量名的集合
|
|
34
40
|
*/
|
|
35
41
|
export function collectObjectPatternBindings(pattern, variables) {
|
|
36
42
|
for (const prop of pattern.properties) {
|
|
37
43
|
if (prop.type === 'RestElement') {
|
|
44
|
+
// 处理剩余运算符
|
|
38
45
|
collectPatternBindings(prop.argument, variables);
|
|
39
46
|
}
|
|
40
47
|
else if (prop.value.type === 'Identifier') {
|
|
48
|
+
// 处理简单标识符属性
|
|
41
49
|
variables.add(prop.value.name);
|
|
42
50
|
}
|
|
43
51
|
else if (prop.value.type === 'ObjectPattern') {
|
|
52
|
+
// 处理嵌套对象解构,递归收集
|
|
44
53
|
collectObjectPatternBindings(prop.value, variables);
|
|
45
54
|
}
|
|
46
55
|
}
|
|
@@ -15,14 +15,22 @@ export interface VIfChainInfo {
|
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* 验证 v-if 链的合法性
|
|
18
|
+
* 检查语法错误,如顺序不当、v-else 不是最后一个等
|
|
19
|
+
* @param children - v-if 链的元素数组
|
|
18
20
|
*/
|
|
19
21
|
export declare function validateVIfChain(children: t.JSXElement[]): void;
|
|
20
22
|
/**
|
|
21
23
|
* 从 JSX 元素数组收集 v-if 链信息
|
|
24
|
+
* 要求所有元素都属于 v-if 链(之前已验证)
|
|
25
|
+
* @param nodes - JSX 元素数组
|
|
26
|
+
* @returns v-if 链信息对象
|
|
22
27
|
*/
|
|
23
28
|
export declare function collectVIfChainInfo(nodes: t.JSXElement[]): VIfChainInfo;
|
|
24
29
|
/**
|
|
25
30
|
* 收集 Fragment 中的 v-if 链
|
|
31
|
+
* 从 Fragment 的子元素中识别多个独立的 v-if 链
|
|
32
|
+
* @param children - Fragment 的子节点数组
|
|
33
|
+
* @returns v-if 链信息数组
|
|
26
34
|
*/
|
|
27
35
|
export declare function collectFragmentVIfChains(children: t.Node[]): Array<VIfChainInfo & {
|
|
28
36
|
endIndex: number;
|
|
@@ -10,24 +10,31 @@ import { isWhitespaceJSXText } from './ast-guards.js';
|
|
|
10
10
|
import { getDirectiveValue, hasDirective, isVElse, isVElseIf, isVIf, isVIfChain } from './jsx-helpers.js';
|
|
11
11
|
/**
|
|
12
12
|
* 验证 v-if 链的合法性
|
|
13
|
+
* 检查语法错误,如顺序不当、v-else 不是最后一个等
|
|
14
|
+
* @param children - v-if 链的元素数组
|
|
13
15
|
*/
|
|
14
16
|
export function validateVIfChain(children) {
|
|
15
17
|
if (children.length === 0)
|
|
16
18
|
return;
|
|
19
|
+
// 第一个元素必须有 v-if 指令
|
|
17
20
|
if (!hasDirective(children[0], 'v-if')) {
|
|
18
21
|
throw createError('E008', children[0], 'First element must have v-if directive');
|
|
19
22
|
}
|
|
23
|
+
// 验证后续元素
|
|
20
24
|
for (let i = 1; i < children.length; i++) {
|
|
21
25
|
const child = children[i];
|
|
22
26
|
const prevChild = children[i - 1];
|
|
23
27
|
const hasVElseIf = hasDirective(child, 'v-else-if');
|
|
24
28
|
const hasVElse = hasDirective(child, 'v-else');
|
|
29
|
+
// 后续元素必须是 v-else-if 或 v-else
|
|
25
30
|
if (!hasVElseIf && !hasVElse) {
|
|
26
31
|
throw createError('E008', child, 'Elements after v-if must have v-else-if or v-else directive');
|
|
27
32
|
}
|
|
33
|
+
// v-else 必须是最后一个元素
|
|
28
34
|
if (hasVElse && i !== children.length - 1) {
|
|
29
35
|
throw createError('E008', child, 'v-else must be the last element');
|
|
30
36
|
}
|
|
37
|
+
// v-else-if 不能接在 v-else 后面
|
|
31
38
|
if (hasVElseIf && hasDirective(prevChild, 'v-else')) {
|
|
32
39
|
throw createError('E008', child, 'v-else-if cannot follow v-else');
|
|
33
40
|
}
|
|
@@ -35,54 +42,72 @@ export function validateVIfChain(children) {
|
|
|
35
42
|
}
|
|
36
43
|
/**
|
|
37
44
|
* 从 JSX 元素数组收集 v-if 链信息
|
|
45
|
+
* 要求所有元素都属于 v-if 链(之前已验证)
|
|
46
|
+
* @param nodes - JSX 元素数组
|
|
47
|
+
* @returns v-if 链信息对象
|
|
38
48
|
*/
|
|
39
49
|
export function collectVIfChainInfo(nodes) {
|
|
40
50
|
const conditions = [];
|
|
51
|
+
// 遍历每个节点,收集对应的条件
|
|
41
52
|
for (const node of nodes) {
|
|
42
53
|
const vIfValue = getDirectiveValue(node, 'v-if');
|
|
43
54
|
if (vIfValue) {
|
|
55
|
+
// v-if 直接使用其条件表达式
|
|
44
56
|
conditions.push(vIfValue);
|
|
45
57
|
continue;
|
|
46
58
|
}
|
|
47
59
|
const vElseIfValue = getDirectiveValue(node, 'v-else-if');
|
|
48
60
|
if (vElseIfValue) {
|
|
61
|
+
// v-else-if 直接使用其条件表达式
|
|
49
62
|
conditions.push(vElseIfValue);
|
|
50
63
|
continue;
|
|
51
64
|
}
|
|
52
65
|
if (hasDirective(node, 'v-else')) {
|
|
66
|
+
// v-else 使用 true 作为条件(默认情况)
|
|
53
67
|
conditions.push(t.booleanLiteral(true));
|
|
54
68
|
continue;
|
|
55
69
|
}
|
|
70
|
+
// 理论上不会走到这里,因为之前已验证
|
|
56
71
|
throw createError('E008', node, 'Element missing v-if/v-else-if/v-else directive');
|
|
57
72
|
}
|
|
58
73
|
return { nodes, conditions, startIndex: 0, endIndex: nodes.length - 1 };
|
|
59
74
|
}
|
|
60
75
|
/**
|
|
61
76
|
* 收集 Fragment 中的 v-if 链
|
|
77
|
+
* 从 Fragment 的子元素中识别多个独立的 v-if 链
|
|
78
|
+
* @param children - Fragment 的子节点数组
|
|
79
|
+
* @returns v-if 链信息数组
|
|
62
80
|
*/
|
|
63
81
|
export function collectFragmentVIfChains(children) {
|
|
64
82
|
const chains = [];
|
|
65
83
|
let i = 0;
|
|
84
|
+
// 遍历所有子节点
|
|
66
85
|
while (i < children.length) {
|
|
67
86
|
const child = children[i];
|
|
87
|
+
// 跳过文本节点
|
|
68
88
|
if (isJSXText(child)) {
|
|
69
89
|
i++;
|
|
70
90
|
continue;
|
|
71
91
|
}
|
|
92
|
+
// 跳过非 JSXElement 节点
|
|
72
93
|
if (!isJSXElement(child)) {
|
|
73
94
|
i++;
|
|
74
95
|
continue;
|
|
75
96
|
}
|
|
97
|
+
// 跳过不属于 v-if 链的元素
|
|
76
98
|
if (!isVIfChain(child)) {
|
|
77
99
|
i++;
|
|
78
100
|
continue;
|
|
79
101
|
}
|
|
102
|
+
// 处理 v-if 开头的链
|
|
80
103
|
if (isVIf(child)) {
|
|
81
104
|
const chain = collectSingleChainFromFragment(children, i);
|
|
82
105
|
chains.push(chain);
|
|
106
|
+
// 跳到链结束的下一个位置
|
|
83
107
|
i = chain.endIndex + 1;
|
|
84
108
|
}
|
|
85
109
|
else if (isVElseIf(child) || isVElse(child)) {
|
|
110
|
+
// v-else-if 或 v-else 不能单独出现
|
|
86
111
|
throw createError(isVElse(child) ? 'E003' : 'E004', child);
|
|
87
112
|
}
|
|
88
113
|
else {
|
|
@@ -93,33 +118,44 @@ export function collectFragmentVIfChains(children) {
|
|
|
93
118
|
}
|
|
94
119
|
/**
|
|
95
120
|
* 从 Fragment 收集单个 v-if 链
|
|
121
|
+
* 从 v-if 开始,收集后续连续的 v-else-if 和 v-else
|
|
122
|
+
* @param children - Fragment 的子节点数组
|
|
123
|
+
* @param startIndex - v-if 起始索引
|
|
124
|
+
* @returns 单个 v-if 链信息
|
|
96
125
|
*/
|
|
97
126
|
function collectSingleChainFromFragment(children, startIndex) {
|
|
98
127
|
const nodes = [children[startIndex]];
|
|
99
128
|
const conditions = [getDirectiveValue(nodes[0], 'v-if')];
|
|
100
129
|
let j = startIndex + 1;
|
|
130
|
+
// 继续收集后续的 v-else-if 和 v-else
|
|
101
131
|
while (j < children.length) {
|
|
102
132
|
const nextChild = children[j];
|
|
133
|
+
// 跳过空白文本节点(允许链元素间有空白)
|
|
103
134
|
if (isJSXText(nextChild) && isWhitespaceJSXText(nextChild)) {
|
|
104
135
|
j++;
|
|
105
136
|
continue;
|
|
106
137
|
}
|
|
138
|
+
// 遇到非 JSXElement,链结束
|
|
107
139
|
if (!isJSXElement(nextChild))
|
|
108
140
|
break;
|
|
141
|
+
// 遇到不属于 v-if 链的元素,链结束
|
|
109
142
|
if (!isVIfChain(nextChild))
|
|
110
143
|
break;
|
|
111
144
|
if (isVElseIf(nextChild)) {
|
|
145
|
+
// 收集 v-else-if
|
|
112
146
|
nodes.push(nextChild);
|
|
113
147
|
conditions.push(getDirectiveValue(nextChild, 'v-else-if'));
|
|
114
148
|
j++;
|
|
115
149
|
}
|
|
116
150
|
else if (isVElse(nextChild)) {
|
|
151
|
+
// 收集 v-else 并结束链
|
|
117
152
|
nodes.push(nextChild);
|
|
118
153
|
conditions.push(t.booleanLiteral(true));
|
|
119
154
|
j++;
|
|
120
155
|
break;
|
|
121
156
|
}
|
|
122
157
|
else {
|
|
158
|
+
// 其他情况,链结束
|
|
123
159
|
break;
|
|
124
160
|
}
|
|
125
161
|
}
|