Skip to content

Commit ab4a415

Browse files
committed
feat: v-let work with v-if and v-for
1 parent 40ba464 commit ab4a415

File tree

5 files changed

+138
-20
lines changed

5 files changed

+138
-20
lines changed

packages/compiler-core/__tests__/transforms/__snapshots__/vLet.spec.ts.snap

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ export function render(_ctx, _cache) {
99
((b=a+_ctx.baz) => _createElementVNode("span", null, [
1010
_createTextVNode(_toDisplayString(b), 1 /* TEXT */)
1111
]))()
12+
]))(),
13+
((x=_ctx.y=_ctx.z) => _createElementVNode("div", null, [
14+
_createTextVNode(_toDisplayString(x) + _toDisplayString(_ctx.y) + _toDisplayString(_ctx.z), 1 /* TEXT */)
15+
]))(),
16+
((exp=_ctx.getExp()) => _createElementVNode("div", null, [
17+
_createTextVNode(_toDisplayString(exp), 1 /* TEXT */)
1218
]))()
1319
]))
1420
}"
@@ -40,6 +46,34 @@ export function render(_ctx, _cache) {
4046
}"
4147
`;
4248

49+
exports[`compiler: v-let transform ok v-if 1`] = `
50+
"import { toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode } from "vue"
51+
52+
export function render(_ctx, _cache) {
53+
return (_openBlock(), _createElementBlock("div", null, [
54+
(_ctx.ok)
55+
? ((a=true) => (_openBlock(), _createElementBlock("div", { key: 0 }, [
56+
_createTextVNode(_toDisplayString(a), 1 /* TEXT */)
57+
])))()
58+
: _createCommentVNode("v-if", true)
59+
]))
60+
}"
61+
`;
62+
63+
exports[`compiler: v-let transform on v-for 1`] = `
64+
"import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, createElementVNode as _createElementVNode } from "vue"
65+
66+
export function render(_ctx, _cache) {
67+
return (_openBlock(), _createElementBlock("div", null, [
68+
(_openBlock(), _createElementBlock(_Fragment, null, _renderList([1,2,3], (i) => {
69+
return ((a=i+1) => _createElementVNode("div", null, [
70+
_createTextVNode(_toDisplayString(a), 1 /* TEXT */)
71+
]))()
72+
}), 64 /* STABLE_FRAGMENT */))
73+
]))
74+
}"
75+
`;
76+
4377
exports[`compiler: v-let transform should work 1`] = `
4478
"import { toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
4579
Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { baseCompile } from '../../src'
1+
import { baseCompile, CompilerOptions } from '../../src'
22

33
describe('compiler: v-let transform', () => {
4-
function compile(content: string) {
4+
function compile(content: string, options: CompilerOptions = {}) {
55
return baseCompile(`<div>${content}</div>`, {
66
mode: 'module',
7-
prefixIdentifiers: true
7+
prefixIdentifiers: true,
8+
...options
89
}).code
910
}
1011

@@ -13,35 +14,76 @@ describe('compiler: v-let transform', () => {
1314
})
1415

1516
test('multiple declare', () => {
16-
expect(compile(
17-
`<div v-let="a=1, b=2">
17+
expect(
18+
compile(
19+
`<div v-let="a=1, b=2">
1820
{{a}} {{b}}
1921
</div>`
20-
)).toMatchSnapshot()
22+
)
23+
).toMatchSnapshot()
2124
})
2225

2326
test('nested v-let', () => {
24-
expect(compile(
25-
`<div v-let="a=1">
27+
expect(
28+
compile(
29+
`<div v-let="a=1">
2630
<span v-let="b=1">{{a}}{{b}}</span>
2731
</div>`
28-
)).toMatchSnapshot()
32+
)
33+
).toMatchSnapshot()
2934
})
3035

3136
test('work with variable', () => {
32-
expect(compile(
33-
`<div v-let="a=msg">
37+
expect(
38+
compile(
39+
`<div v-let="a=msg">
3440
<span v-let="b=a">{{b}}</span>
3541
</div>`
36-
)).toMatchSnapshot()
42+
)
43+
).toMatchSnapshot()
3744
})
3845

3946
test('complex expression', () => {
40-
expect(compile(
41-
`<div v-let="a=foo+bar">
42-
<span v-let="b=a+baz">{{b}}</span>
43-
</div>`
44-
)).toMatchSnapshot()
47+
expect(
48+
compile(`
49+
<div v-let="a=foo+bar">
50+
<span v-let="b=a+baz">{{b}}</span>
51+
</div>
52+
<div v-let="x=y=z">{{x}}{{y}}{{z}}</div>
53+
<div v-let="exp=getExp()">{{exp}}</div>
54+
`)
55+
).toMatchSnapshot()
56+
})
57+
58+
test('on v-for', () => {
59+
expect(
60+
compile(`
61+
<div v-for="i in [1,2,3]" v-let="a=i+1">
62+
{{ a }}
63+
</div>
64+
`)
65+
).toMatchSnapshot()
4566
})
4667

68+
test('ok v-if', () => {
69+
expect(
70+
compile(`
71+
<div v-if="ok" v-let="a=true" >
72+
{{ a }}
73+
</div>
74+
`)
75+
).toMatchSnapshot()
76+
})
77+
78+
test('error', () => {
79+
const onError = jest.fn()
80+
expect(compile(`<div v-let="a=,b=1">{{a}}</div>`, { onError }))
81+
expect(onError.mock.calls).toMatchInlineSnapshot(`
82+
[
83+
[
84+
[SyntaxError: Error parsing JavaScript expression: Unexpected token (1:3)],
85+
],
86+
]
87+
`)
88+
})
4789
})

packages/compiler-core/src/transforms/vFor.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export const transformFor = createStructuralDirectiveTransform(
6161
]) as ForRenderListExpression
6262
const isTemplate = isTemplateNode(node)
6363
const memo = findDir(node, 'memo')
64+
const vLet = findDir(node, 'let')
6465
const keyProp = findProp(node, `key`)
6566
const keyExp =
6667
keyProp &&
@@ -228,10 +229,19 @@ export const transformFor = createStructuralDirectiveTransform(
228229
createSimpleExpression(String(context.cached++))
229230
)
230231
} else {
232+
let child
233+
if (vLet) {
234+
child = createCallExpression(
235+
createFunctionExpression([vLet.exp!], childBlock)
236+
)
237+
} else {
238+
child = childBlock
239+
}
240+
231241
renderExp.arguments.push(
232242
createFunctionExpression(
233243
createForLoopParams(forNode.parseResult),
234-
childBlock,
244+
child,
235245
true /* force newline */
236246
) as ForIteratorExpression
237247
)

packages/compiler-core/src/transforms/vIf.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ import {
2323
locStub,
2424
CacheExpression,
2525
ConstantTypes,
26-
MemoExpression
26+
MemoExpression,
27+
VNodeCall,
28+
CallExpression,
29+
FunctionExpression
2730
} from '../ast'
2831
import { createCompilerError, ErrorCodes } from '../errors'
2932
import { processExpression } from './transformExpression'
@@ -298,7 +301,12 @@ function createChildrenCodegenNode(
298301
const ret = (firstChild as ElementNode).codegenNode as
299302
| BlockCodegenNode
300303
| MemoExpression
301-
const vnodeCall = getMemoedVNodeCall(ret)
304+
305+
const vnodeCall = findDir(firstChild, 'let')
306+
? (((ret as CallExpression).callee as FunctionExpression)
307+
.returns as VNodeCall)
308+
: getMemoedVNodeCall(ret)
309+
302310
// Change createVNode to createBlock.
303311
if (vnodeCall.type === NodeTypes.VNODE_CALL) {
304312
makeBlock(vnodeCall, context)

packages/compiler-ssr/__tests__/ssrVLet.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,28 @@ describe('ssr: v-let', () => {
3838
}"
3939
`)
4040
})
41+
42+
test('ok v-if', () => {
43+
expect(
44+
compile(`
45+
<div v-if="ok" v-let="a=true" >
46+
{{ a }}
47+
</div>
48+
`).code
49+
).toMatchInlineSnapshot(`
50+
"const { ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate } = require("vue/server-renderer")
51+
52+
return function ssrRender(_ctx, _push, _parent, _attrs) {
53+
if (_ctx.ok) {
54+
_push(\`<div\${_ssrRenderAttrs(_attrs)}>\`)
55+
;((a=true) => {
56+
_push(\`\${_ssrInterpolate(a)}\`)
57+
})()
58+
_push(\`</div>\`)
59+
} else {
60+
_push(\`<!---->\`)
61+
}
62+
}"
63+
`)
64+
})
4165
})

0 commit comments

Comments
 (0)