Skip to content

Commit e7e3b1c

Browse files
committed
revert: "refactor: id rewrite of vapor v-for"
This reverts commit 31f497b.
1 parent 31f497b commit e7e3b1c

File tree

9 files changed

+100
-123
lines changed

9 files changed

+100
-123
lines changed

packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap

Lines changed: 9 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

33
exports[`compiler: v-for > basic v-for 1`] = `
4-
"import { template as _template, fragment as _fragment, renderEffect as _renderEffect, children as _children, on as _on, setText as _setText, createFor as _createFor, append as _append } from 'vue/vapor';
4+
"import { template as _template, fragment as _fragment, children as _children, on as _on, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, append as _append } from 'vue/vapor';
55
66
export function render(_ctx) {
77
const t0 = _template("<div></div>")
88
const t1 = _fragment()
99
const n0 = t1()
1010
const n1 = _createFor(() => (_ctx.items), (_block) => {
11-
let item
12-
_renderEffect(() => {
13-
([item] = _block.s);
14-
})
1511
const n2 = t0()
1612
const { 0: [n3],} = _children(n2)
17-
_on(n3, "click", $event => (_ctx.remove(item)))
18-
_renderEffect(() => {
13+
_on(n3, "click", $event => (_ctx.remove(_block.s[0])))
14+
const _updateEffect = () => {
15+
const [item] = _block.s
1916
_setText(n3, item)
20-
})
21-
return n2
17+
}
18+
_renderEffect(_updateEffect)
19+
return [n2, _updateEffect]
2220
})
2321
_append(n0, n1)
2422
return n0
2523
}"
2624
`;
2725

28-
exports[`compiler: v-for > no value 1`] = `
26+
exports[`compiler: v-for > basic v-for 2`] = `
2927
"import { template as _template, fragment as _fragment, createFor as _createFor, append as _append } from 'vue/vapor';
3028
3129
export function render(_ctx) {
@@ -34,37 +32,7 @@ export function render(_ctx) {
3432
const n0 = t1()
3533
const n1 = _createFor(() => (_ctx.items), (_block) => {
3634
const n2 = t0()
37-
return n2
38-
})
39-
_append(n0, n1)
40-
return n0
41-
}"
42-
`;
43-
44-
exports[`compiler: v-for > object de-structured value 1`] = `
45-
"import { template as _template, fragment as _fragment, renderEffect as _renderEffect, children as _children, createTextNode as _createTextNode, append as _append, setText as _setText, createFor as _createFor } from 'vue/vapor';
46-
47-
export function render(_ctx) {
48-
const t0 = _template("<span></span>")
49-
const t1 = _fragment()
50-
const n0 = t1()
51-
const n1 = _createFor(() => (_ctx.items), (_block) => {
52-
let id, value
53-
_renderEffect(() => {
54-
([{ id, value }] = _block.s);
55-
})
56-
const n2 = t0()
57-
const { 0: [n5],} = _children(n2)
58-
const n3 = _createTextNode()
59-
const n4 = _createTextNode()
60-
_append(n5, n3, n4)
61-
_renderEffect(() => {
62-
_setText(n3, id)
63-
})
64-
_renderEffect(() => {
65-
_setText(n4, value)
66-
})
67-
return n2
35+
return [n2, () => {}]
6836
})
6937
_append(n0, n1)
7038
return n0

packages/compiler-vapor/__tests__/transforms/vFor.spec.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,8 @@ describe('compiler: v-for', () => {
6666
expect((ir.operation[0] as ForIRNode).render.effect).lengthOf(1)
6767
})
6868

69-
test('no value', () => {
69+
test('basic v-for', () => {
7070
const { code } = compileWithVFor(`<div v-for=" of items">item</div>`)
7171
expect(code).matchSnapshot()
7272
})
73-
74-
test('object de-structured value', () => {
75-
const { code } = compileWithVFor(
76-
'<span v-for="({ id, value }) in items">{{ id }}{{ value }}</span>',
77-
)
78-
expect(code).matchSnapshot()
79-
})
8073
})

packages/compiler-vapor/src/generate.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import {
77
advancePositionWithMutation,
88
locStub,
99
} from '@vue/compiler-dom'
10-
import type { RootIRNode, VaporHelper } from './ir'
10+
import type { IREffect, RootIRNode, VaporHelper } from './ir'
1111
import { SourceMapGenerator } from 'source-map-js'
12-
import { extend, isString } from '@vue/shared'
12+
import { extend, isString, remove } from '@vue/shared'
1313
import type { ParserPlugin } from '@babel/parser'
1414
import { genTemplate } from './generators/template'
1515
import { genBlockFunctionContent } from './generators/block'
@@ -69,19 +69,22 @@ export class CodegenContext {
6969
return `_${name}`
7070
}
7171

72-
identifiers: Record<string, number> = Object.create(null)
73-
withId = <T>(fn: () => T, ids: string[]): T => {
72+
identifiers: Record<string, string[]> = Object.create(null)
73+
withId = <T>(fn: () => T, map: Record<string, string | null>): T => {
7474
const { identifiers } = this
75+
const ids = Object.keys(map)
76+
7577
for (const id of ids) {
76-
if (identifiers[id] === undefined) identifiers[id] = 0
77-
identifiers[id]!++
78+
identifiers[id] ||= []
79+
identifiers[id].unshift(map[id] || id)
7880
}
7981

8082
const ret = fn()
81-
ids.forEach(id => identifiers[id]!--)
83+
ids.forEach(id => remove(identifiers[id], map[id] || id))
8284

8385
return ret
8486
}
87+
genEffect?: (effects: IREffect[]) => CodeFragment[]
8588

8689
constructor(
8790
public ir: RootIRNode,

packages/compiler-vapor/src/generators/block.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,13 @@ export function genBlockFunction(
2121
oper: BlockFunctionIRNode,
2222
context: CodegenContext,
2323
args: CodeFragment[] = [],
24-
preamble: CodeFragment[] = [],
25-
returnValue?: CodeFragment[],
24+
returnValue?: () => CodeFragment[],
2625
): CodeFragment[] {
2726
return [
2827
'(',
2928
...args,
3029
') => {',
3130
INDENT_START,
32-
...preamble,
3331
...genBlockFunctionContent(oper, context, returnValue),
3432
INDENT_END,
3533
NEWLINE,
@@ -40,7 +38,7 @@ export function genBlockFunction(
4038
export function genBlockFunctionContent(
4139
ir: BlockFunctionIRNode | RootIRNode,
4240
context: CodegenContext,
43-
returnValue?: CodeFragment[],
41+
returnValue?: () => CodeFragment[],
4442
): CodeFragment[] {
4543
const { vaporHelper } = context
4644
const [frag, push] = buildCodeFragment(
@@ -67,7 +65,11 @@ export function genBlockFunctionContent(
6765
push(...genOperations(ir.operation, context))
6866
push(...genEffects(ir.effect, context))
6967

70-
push(NEWLINE, 'return ', ...(returnValue || [`n${ir.dynamic.id}`]))
68+
push(
69+
NEWLINE,
70+
'return ',
71+
...(returnValue ? returnValue() : [`n${ir.dynamic.id}`]),
72+
)
7173

7274
return frag
7375
}

packages/compiler-vapor/src/generators/event.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,9 @@ export function genSetEvent(
4545
const hasMultipleStatements = exp.content.includes(`;`)
4646

4747
if (isInlineStatement) {
48-
const expr = context.withId(
49-
() => genExpression(exp, context),
50-
['$event'],
51-
)
48+
const expr = context.withId(() => genExpression(exp, context), {
49+
$event: null,
50+
})
5251
return [
5352
'$event => ',
5453
hasMultipleStatements ? '{' : '(',

packages/compiler-vapor/src/generators/expression.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ function genIdentifier(
8888
const { inline, bindingMetadata } = options
8989
let name: string | undefined = id
9090

91-
if (identifiers[id]) {
92-
return [id, NewlineType.None, loc]
91+
const idMap = identifiers[id]
92+
if (idMap && idMap.length) {
93+
return [idMap[0], NewlineType.None, loc]
9394
}
9495

9596
if (inline) {

packages/compiler-vapor/src/generators/for.ts

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,11 @@ import {
66
INDENT_END,
77
INDENT_START,
88
NEWLINE,
9+
buildCodeFragment,
910
} from '../generate'
10-
import type { ForIRNode } from '../ir'
11-
import {
12-
NewlineType,
13-
type SimpleExpressionNode,
14-
walkIdentifiers,
15-
} from '@vue/compiler-dom'
16-
import type { ArrowFunctionExpression } from '@babel/types'
11+
import type { ForIRNode, IREffect } from '../ir'
12+
import { genOperations } from './operation'
13+
import { NewlineType } from '@vue/compiler-dom'
1714

1815
export function genFor(
1916
oper: ForIRNode,
@@ -22,63 +19,73 @@ export function genFor(
2219
const { call, vaporHelper } = context
2320
const { source, value, key, render } = oper
2421

22+
const rawValue = value && value.content
2523
const rawKey = key && key.content
24+
2625
const sourceExpr = ['() => (', ...genExpression(source, context), ')']
27-
const valueIds = value ? extractParams(value) : new Set<string>()
28-
const keyIds = key ? extractParams(key) : new Set<string>()
29-
const ids = [...valueIds, ...keyIds]
26+
let updateFn = '_updateEffect'
27+
context.genEffect = genEffectInFor
3028

31-
let preamble: CodeFragment[] = []
32-
if (value || rawKey) {
33-
const assignment: CodeFragment[] = ['let ', ids.join(', ')]
29+
const idMap: Record<string, string> = {}
30+
if (rawValue) idMap[rawValue] = `_block.s[0]`
31+
if (rawKey) idMap[rawKey] = `_block.s[1]`
3432

35-
preamble = [
36-
NEWLINE,
37-
...assignment,
38-
NEWLINE,
39-
...call(vaporHelper('renderEffect'), [
40-
'() => {',
41-
INDENT_START,
42-
NEWLINE,
43-
'(',
44-
'[',
45-
value && [value.content, NewlineType.None, value.loc],
46-
rawKey && ', ',
47-
rawKey && [rawKey, NewlineType.None, key.loc],
48-
'] = _block.s',
49-
');',
50-
INDENT_END,
51-
NEWLINE,
52-
'}',
53-
]),
54-
]
55-
}
33+
const blockRet = (): CodeFragment[] => [
34+
`[n${render.dynamic.id!}, ${updateFn}]`,
35+
]
5636

57-
const blockRet: CodeFragment[] = [`n${render.dynamic.id!}`]
5837
const blockFn = context.withId(
59-
() => genBlockFunction(render, context, ['_block'], preamble, blockRet),
60-
ids,
38+
() => genBlockFunction(render, context, ['_block'], blockRet),
39+
idMap,
6140
)
6241

42+
context.genEffect = undefined
43+
6344
return [
6445
NEWLINE,
6546
`const n${oper.id} = `,
6647
...call(vaporHelper('createFor'), sourceExpr, blockFn),
6748
]
68-
}
6949

70-
function extractParams(node: SimpleExpressionNode) {
71-
const ids = new Set<string>()
72-
if (node.ast === null || node.ast === false) {
73-
ids.add(node.content)
74-
} else {
75-
walkIdentifiers(
76-
node.ast as ArrowFunctionExpression,
77-
(id, parent, parentStack, isReference, isLocal) => {
78-
if (isLocal) ids.add(id.name)
79-
},
80-
true,
81-
)
50+
function genEffectInFor(effects: IREffect[]): CodeFragment[] {
51+
if (!effects.length) {
52+
updateFn = '() => {}'
53+
return []
54+
}
55+
56+
const [frag, push] = buildCodeFragment(INDENT_START)
57+
// const [value, key] = _block.s
58+
if (rawValue || rawKey) {
59+
push(
60+
NEWLINE,
61+
'const ',
62+
'[',
63+
rawValue && [rawValue, NewlineType.None, value.loc],
64+
rawKey && ', ',
65+
rawKey && [rawKey, NewlineType.None, key.loc],
66+
'] = _block.s',
67+
)
68+
}
69+
70+
const idMap: Record<string, string | null> = {}
71+
if (value) idMap[value.content] = null
72+
if (key) idMap[key.content] = null
73+
context.withId(() => {
74+
effects.forEach(effect =>
75+
push(...genOperations(effect.operations, context)),
76+
)
77+
}, idMap)
78+
79+
push(INDENT_END)
80+
81+
return [
82+
NEWLINE,
83+
`const ${updateFn} = () => {`,
84+
...frag,
85+
NEWLINE,
86+
'}',
87+
NEWLINE,
88+
`${vaporHelper('renderEffect')}(${updateFn})`,
89+
]
8290
}
83-
return ids
8491
}

packages/compiler-vapor/src/generators/operation.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export function genOperations(opers: OperationNode[], context: CodegenContext) {
2525
return frag
2626
}
2727

28-
export function genOperation(
28+
function genOperation(
2929
oper: OperationNode,
3030
context: CodegenContext,
3131
): CodeFragment[] {
@@ -60,14 +60,17 @@ export function genOperation(
6060
}
6161

6262
export function genEffects(effects: IREffect[], context: CodegenContext) {
63+
if (context.genEffect) {
64+
return context.genEffect(effects)
65+
}
6366
const [frag, push] = buildCodeFragment()
6467
for (const effect of effects) {
6568
push(...genEffect(effect, context))
6669
}
6770
return frag
6871
}
6972

70-
export function genEffect({ operations }: IREffect, context: CodegenContext) {
73+
function genEffect({ operations }: IREffect, context: CodegenContext) {
7174
const { vaporHelper } = context
7275
const [frag, push] = buildCodeFragment(
7376
NEWLINE,

packages/runtime-vapor/src/for.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ interface ForBlock extends Fragment {
1515

1616
export const createFor = (
1717
src: () => any[] | Record<string, string> | Set<any> | Map<any, any>,
18-
renderItem: (block: ForBlock) => Block,
18+
renderItem: (block: ForBlock) => [Block, () => void],
1919
getKey: ((item: any, index: number) => any) | null,
2020
getMemo?: (item: any) => any[],
2121
hydrationNode?: Node,
@@ -47,8 +47,9 @@ export const createFor = (
4747
memo: getMemo && getMemo(item),
4848
[fragmentKey]: true,
4949
})
50-
block.nodes = scope.run(() => renderItem(block))!
51-
block.update = () => scope.effects.forEach(effect => effect.run())
50+
const res = scope.run(() => renderItem(block))!
51+
block.nodes = res[0]
52+
block.update = res[1]
5253
if (getMemo) block.update()
5354
if (parent) insert(block.nodes, parent, anchor)
5455
return block

0 commit comments

Comments
 (0)