Skip to content

Commit 0286bde

Browse files
committed
refactor: v-for
1 parent 949baa7 commit 0286bde

File tree

4 files changed

+51
-35
lines changed

4 files changed

+51
-35
lines changed

playground/virtual-dom/App.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ defineRender((
8282
<Comp
8383
v-permission={`"post"`}
8484
v-model_number={count.value}
85-
icon1={`"icon1"`}
8685
icon={(
8786
<i id="id">
8887
{count.value
@@ -95,6 +94,7 @@ defineRender((
9594
"+"
9695
</i>
9796
)}
97+
icon1={`"icon1"`}
9898
getChildren={() => {
9999
const A = (
100100
<Comp icon={<i>"-"</i>} />

playground/virtual-dom/for.vue

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,32 @@ function Comp() {
1212
1313
const count = ref(0)
1414
defineRender(
15-
<>
15+
<div>
1616
<button onClick={() => count.value++}>
1717
{count.value}
1818
</button>
19+
<div>
20+
{count.value}
21+
</div>
22+
{
23+
Array.from({ length: 3 }).map((_, index) => (
24+
<span>
25+
{index}
26+
</span>
27+
))
28+
}
29+
{' '}
30+
{
31+
Array.from({ length: 3 }).map((_, index) => {
32+
const idx = index + 1
33+
return (
34+
<span>
35+
{idx}
36+
</span>
37+
)
38+
})
39+
}
1940
<Comp v-for={i in 3} key={i} ref={() => {}} />
20-
</>,
41+
</div>,
2142
)
2243
</script>

src/core/transform.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,38 @@ import type { Node } from '@babel/types'
99
import type { Options } from '../types'
1010
import { transformVIf } from './v-if'
1111
import { transformVFor } from './v-for'
12-
import { getReturnExpression, isConditionalExpression, isJSXElement, isJSXExpression, isLogicalExpression, isMapCallExpression } from './common'
12+
import { isConditionalExpression, isJSXElement, isJSXExpression, isLogicalExpression, isMapCallExpression } from './common'
13+
14+
export type RootNodes = {
15+
node: Node
16+
postCallbacks?: ((() => void) | undefined)[]
17+
isAttributeValue?: boolean
18+
}[]
1319

1420
export function transformVueJsxVapor(
1521
code: string,
1622
id: string,
1723
options: Options,
1824
) {
1925
const s = new MagicString(code)
20-
const exclude: Node[] = []
2126
let hasTextNode = false
22-
const rootNodes: {
23-
node: Node
24-
postCallbacks: ((() => void) | undefined)[]
25-
isAttributeValue?: boolean
26-
}[] = []
27+
const rootNodes: RootNodes = []
2728
let postCallbacks: ((() => void) | undefined)[] = []
2829
walkAST<Node>(babelParse(code, getLang(id)), {
2930
enter(node, parent) {
3031
if (
3132
parent?.type !== 'JSXExpressionContainer'
3233
&& !isJSXExpression(parent)
3334
&& isJSXExpression(node)
34-
&& !exclude.includes(node)
3535
) {
3636
rootNodes.unshift({
3737
node,
3838
postCallbacks: [],
3939
})
40-
postCallbacks = rootNodes[0].postCallbacks
40+
postCallbacks = rootNodes[0].postCallbacks!
4141
}
4242
else if (
43-
(parent?.type === 'JSXAttribute')
43+
parent?.type === 'JSXAttribute'
4444
&& node.type === 'JSXExpressionContainer'
4545
&& /("|<.*?\/.*?>)/.test(s.sliceNode(node.expression))
4646
) {
@@ -49,7 +49,7 @@ export function transformVueJsxVapor(
4949
postCallbacks: [],
5050
isAttributeValue: true,
5151
})
52-
postCallbacks = rootNodes[0].postCallbacks
52+
postCallbacks = rootNodes[0].postCallbacks!
5353
}
5454

5555
if (
@@ -102,9 +102,8 @@ export function transformVueJsxVapor(
102102
isMapCallExpression(node)
103103
) {
104104
postCallbacks.unshift(
105-
transformVFor(node, parent, s),
105+
transformVFor(node, parent, rootNodes, s),
106106
)
107-
exclude.unshift(getReturnExpression(node.arguments[0])!)
108107
}
109108
else if (
110109
isConditionalExpression(node)
@@ -126,12 +125,12 @@ export function transformVueJsxVapor(
126125
else if (!isJSXExpression(node.expression)) {
127126
s.overwrite(node.start!, node.start! + 1, '<component :is="__createTextVNode(')
128127
s.overwrite(node.end! - 1, node.end!, ')" />')
128+
129129
if (
130130
/("|<.*?\/.*?>)/.test(s.sliceNode(node.expression))
131131
) {
132132
rootNodes.unshift({
133133
node: node.expression,
134-
postCallbacks: [],
135134
isAttributeValue: true,
136135
})
137136
}
@@ -171,9 +170,10 @@ export function transformVueJsxVapor(
171170
return content
172171
}
173172
}
173+
174174
const placeholders: string[] = []
175175
for (const { node, postCallbacks, isAttributeValue } of rootNodes) {
176-
postCallbacks.forEach(callback => callback?.())
176+
postCallbacks?.forEach(callback => callback?.())
177177

178178
const result = compile(node)
179179
.replaceAll(/__PLACEHOLDER_(\d)/g, (_, $1) => placeholders[$1])
@@ -189,7 +189,7 @@ export function transformVueJsxVapor(
189189
importSet.add('createTextVNode as _createTextVNode')
190190
importSet.add('toDisplayString as _toDisplayString')
191191
s.prepend(
192-
`const __createTextVNode = (node) => node?.__v_isVNode || typeof node ==='function' ? node: _createTextVNode(_toDisplayString(node));`,
192+
`const __createTextVNode = (node) => node?.__v_isVNode || typeof node === 'function' || (Array.isArray(node) && node[0]?.__v_isVNode) ? node : _createTextVNode(_toDisplayString(node));`,
193193
)
194194
}
195195

src/core/v-for.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import type { MagicString } from '@vue-macros/common'
22
import type { CallExpression, Node } from '@babel/types'
3-
import { addAttribute, getReturnExpression, isJSXElement, overwrite } from './common'
3+
import type { RootNodes } from './transform'
44

55
export function transformVFor(
66
node: CallExpression,
77
parent: Node | null | undefined,
8+
rootNodes: RootNodes,
89
s: MagicString,
910
) {
1011
const { callee, arguments: [argument] } = node
@@ -23,21 +24,15 @@ export function transformVFor(
2324
: null
2425
const directive = ` v-for="(${left}) in ${right}"`
2526

26-
const returnExpression = getReturnExpression(argument)
27-
if (!returnExpression)
28-
return
29-
30-
if (isJSXElement(returnExpression)) {
31-
addAttribute(returnExpression, directive, s)
32-
33-
return () => {
34-
s.overwrite(start, returnExpression.start!, '')
35-
s.overwrite(returnExpression.end!, end, '')
36-
}
37-
}
38-
27+
rootNodes.unshift({
28+
node: {
29+
...argument.body,
30+
type: 'ReturnStatement',
31+
},
32+
isAttributeValue: true,
33+
})
3934
return () => {
40-
s.overwrite(start, returnExpression.start!, `<template${directive}>`)
41-
s.overwrite(returnExpression.end!, end, `</template>`)
35+
s.overwrite(start, argument.body.start!, `<template${directive}><component :is="()=>`)
36+
s.overwrite(argument.body.end!, end, `"/></template>`)
4237
}
4338
}

0 commit comments

Comments
 (0)