Skip to content

Commit 9d1756e

Browse files
committed
chore: 清理冗余代码模块;调整模块结构
1 parent c4fe86e commit 9d1756e

File tree

13 files changed

+224
-310
lines changed

13 files changed

+224
-310
lines changed

src/common/AsyncComponents.ts

Lines changed: 0 additions & 53 deletions
This file was deleted.

src/common/AsyncImports.ts

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/plugin/async-component-processor.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import process from 'node:process'
44
import { logger } from '../common/Logger'
55
import {
66
COMPONENT_PLACEHOLDER,
7+
DEFINE_COMPONENT,
78
DEFINE_OPTIONS,
89
filterMacro,
910
getComponentPlaceholder,
@@ -67,14 +68,14 @@ export function AsyncComponentProcessor(enableLogger: boolean): Plugin {
6768

6869
if (scriptAst) {
6970
// 有些是使用 defineComponent 声明的
70-
const macroNodes = filterMacro(scriptAst.body, 'defineComponent')
71+
const macroNodes = filterMacro(scriptAst.body, DEFINE_COMPONENT)
7172
collectPlaceholder(macroNodes?.[0]?.arguments?.[0])
7273
const [defaultExport] = getDefaultExports(scriptAst)
7374
collectPlaceholder(defaultExport?.declaration)
7475
}
7576
if (setupAst) {
76-
const macroNodes = filterMacro(setupAst.body)
77-
if (macroNodes.length > 1) {
77+
const macroNodes = filterMacro(setupAst.body, DEFINE_OPTIONS)
78+
if (macroNodes.length > 1) { // 多个 defineOptions 宏是不允许的
7879
throw new SyntaxError(`duplicate ${DEFINE_OPTIONS}() call`)
7980
}
8081
collectPlaceholder(macroNodes?.[0]?.arguments?.[0])

src/utils/ast/common.ts

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import type { ExportDefaultDeclaration, Node, ObjectExpression, Program, TemplateLiteral } from '@babel/types'
2+
import { walkAST } from 'ast-kit'
3+
4+
export function getDefaultExports(program: Program) {
5+
const defaultExports: ExportDefaultDeclaration[] = []
6+
7+
walkAST(program, {
8+
enter(node) {
9+
// 匹配 export default
10+
// 虽然标准语法中只支持一个默认导出,但是这里支持多个默认导出节点的收集
11+
if (node.type === 'ExportDefaultDeclaration') {
12+
defaultExports.push(node)
13+
}
14+
// export 只能出现在顶层,遇到块级作用域直接跳过
15+
if (node.type === 'BlockStatement' || node.type === 'FunctionDeclaration') {
16+
this.skip()
17+
}
18+
},
19+
})
20+
21+
return defaultExports
22+
}
23+
24+
export function serializeObjectExpression(node: ObjectExpression) {
25+
// 确保传入的是对象表达式
26+
if (node.type !== 'ObjectExpression') {
27+
throw new Error('Not an ObjectExpression')
28+
}
29+
30+
const result: Record<string, unknown> = {}
31+
32+
node.properties.forEach((prop) => {
33+
// 处理常见的属性(Property),排除 SpreadElement(如 ...obj)
34+
if (prop.type === 'ObjectProperty') {
35+
let key
36+
37+
// 处理 key (例如 { a: 1 } 或 { "a": 1 })
38+
if (prop.computed) {
39+
// 如果是计算属性 [key]: value,简单静态处理可能拿不到值,这里通常抛错或跳过
40+
console.warn('Computed properties are not supported in static serialization')
41+
return
42+
}
43+
else {
44+
// 处理 Identifier (a) 或 StringLiteral ("a")
45+
// @ts-expect-error ignore
46+
key = prop.key.name || prop.key.value
47+
}
48+
49+
// 处理 value (递归解析)
50+
// 如果存在相同 key,则将会记录到最后一项
51+
result[key] = parseValue(prop.value)
52+
}
53+
})
54+
55+
return result
56+
}
57+
58+
export function parseValue(node?: Node | null): unknown {
59+
if (!node)
60+
return node
61+
62+
switch (node.type) {
63+
case 'StringLiteral':
64+
case 'NumericLiteral':
65+
case 'BooleanLiteral':
66+
return node.value
67+
case 'NullLiteral':
68+
return null
69+
case 'BigIntLiteral':
70+
return BigInt(node.value)
71+
case 'RegExpLiteral':
72+
return new RegExp(node.pattern, node.flags)
73+
case 'ObjectExpression':
74+
return serializeObjectExpression(node)
75+
case 'ArrayExpression':
76+
return node.elements.map((el) => {
77+
return el ? parseValue(el) : null
78+
})
79+
case 'BinaryExpression': {
80+
const left = parseValue(node.left)
81+
const right = parseValue(node.right)
82+
83+
// 如果左右任一端无法静态解析(例如引用了变量),则整体返回 undefined 或占位符
84+
if ((typeof left === 'string' && left.startsWith('[')) || (typeof right === 'string' && right.startsWith('['))) {
85+
return `[BinaryExpression: ${node.operator}]`
86+
}
87+
88+
switch (node.operator) {
89+
case '+': return (left as any) + (right as any)
90+
case '-': return (left as any) - (right as any)
91+
case '*': return (left as any) * (right as any)
92+
case '/': return (left as any) / (right as any)
93+
case '%': return (left as any) % (right as any)
94+
case '**': return (left as any) ** (right as any)
95+
// eslint-disable-next-line eqeqeq
96+
case '==': return left == right
97+
case '===': return left === right
98+
// eslint-disable-next-line eqeqeq
99+
case '!=': return left != right
100+
case '!==': return left !== right
101+
case '>': return (left as any) > (right as any)
102+
case '<': return (left as any) < (right as any)
103+
default: return `[Unsupported Operator: ${node.operator}]`
104+
}
105+
}
106+
// 逻辑表达式
107+
case 'LogicalExpression': {
108+
const left = parseValue(node.left)
109+
// 模拟 JS 的短路逻辑
110+
if (node.operator === '&&')
111+
return left && parseValue(node.right)
112+
if (node.operator === '||')
113+
return left || parseValue(node.right)
114+
if (node.operator === '??')
115+
return left ?? parseValue(node.right)
116+
return undefined
117+
}
118+
case 'TemplateLiteral':
119+
// 如果是没有变量的模板字符串
120+
return parseTemplateLiteral(node)
121+
case 'UnaryExpression': {
122+
const { operator, argument } = node
123+
const value = parseValue(argument) // 递归获取参数值
124+
125+
// 如果参数无法解析出静态值,则整体无法解析
126+
if (value === undefined)
127+
return undefined
128+
129+
switch (operator) {
130+
case '-': return -(value as any)
131+
case '+': return +(value as any)
132+
case '!': return !value
133+
case '~': return ~(value as any)
134+
case 'void': return undefined
135+
default: return `[${operator}: ${value}]` // 其余如 typeof, delete 无法静态化
136+
}
137+
}
138+
case 'Identifier':
139+
// 如果遇到变量引用,静态环境下无法得知具体值,通常返回变量名字符串或占位符
140+
return `[Identifier: ${node.name}]`
141+
default:
142+
return `[Unhandled: ${node.type}]`
143+
}
144+
}
145+
146+
/**
147+
* 模版字符串 ast 转成文本
148+
* @param node TemplateLiteral
149+
*/
150+
export function parseTemplateLiteral(node: TemplateLiteral) {
151+
let result = ''
152+
const quasis = node.quasis
153+
const expressions = node.expressions
154+
155+
for (let i = 0; i < quasis.length; i++) {
156+
result += quasis[i].value.cooked
157+
158+
if (i < expressions.length) {
159+
result += `\${${expressions[i].type}}`
160+
}
161+
}
162+
return result
163+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { ObjectExpression } from '@babel/types'
2+
import { serializeObjectExpression } from './common'
3+
import { COMPONENT_PLACEHOLDER } from './constant'
4+
5+
export function hasComponentPlaceholder(node: ObjectExpression): boolean {
6+
return node.properties.some(
7+
prop =>
8+
(prop.type === 'ObjectProperty' || prop.type === 'ObjectMethod')
9+
&& prop.key.type === 'Identifier'
10+
&& (prop.key.name === COMPONENT_PLACEHOLDER),
11+
)
12+
}
13+
14+
export function getComponentPlaceholder(node: ObjectExpression) {
15+
if (node?.type !== 'ObjectExpression') {
16+
return
17+
}
18+
if (!hasComponentPlaceholder(node)) {
19+
return
20+
}
21+
22+
// 序列化 ast 为对象
23+
const obj = serializeObjectExpression(node)
24+
if (COMPONENT_PLACEHOLDER in obj && typeof obj[COMPONENT_PLACEHOLDER] === 'object') {
25+
return obj[COMPONENT_PLACEHOLDER] as typeof obj
26+
}
27+
}

src/utils/ast/constant.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const DEFINE_OPTIONS = 'defineOptions'
2+
export const DEFINE_COMPONENT = 'defineComponent'
3+
export const COMPONENT_PLACEHOLDER = 'componentPlaceholder'

0 commit comments

Comments
 (0)