fix(compiler): generate correct fragment children when it contains single text node or slot outlet

This commit is contained in:
Evan You
2019-10-01 23:53:52 -04:00
parent a477594d65
commit 3a95a2f148
10 changed files with 153 additions and 48 deletions

View File

@@ -14,7 +14,9 @@ return function render() {
_toString(world.burn()),
(_openBlock(), ok
? _createBlock(\\"div\\", { key: 0 }, \\"yes\\")
: _createBlock(_Fragment, { key: 1 }, \\"no\\")),
: _createBlock(_Fragment, { key: 1 }, [
\\"no\\"
])),
_createVNode(_Fragment, null, _renderList(list, (value, index) => {
return (_openBlock(), _createBlock(\\"div\\", null, [
_createVNode(\\"span\\", null, _toString(value + index))
@@ -37,7 +39,9 @@ return function render() {
toString(_ctx.world.burn()),
(openBlock(), (_ctx.ok)
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
: createBlock(Fragment, { key: 1 }, \\"no\\")),
: createBlock(Fragment, { key: 1 }, [
\\"no\\"
])),
createVNode(Fragment, null, renderList(_ctx.list, (value, index) => {
return (openBlock(), createBlock(\\"div\\", null, [
createVNode(\\"span\\", null, toString(value + index))
@@ -59,7 +63,9 @@ export default function render() {
_toString(_ctx.world.burn()),
(openBlock(), (_ctx.ok)
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
: createBlock(Fragment, { key: 1 }, \\"no\\")),
: createBlock(Fragment, { key: 1 }, [
\\"no\\"
])),
createVNode(Fragment, null, renderList(_ctx.list, (value, index) => {
return (openBlock(), createBlock(\\"div\\", null, [
createVNode(\\"span\\", null, _toString(value + index))

View File

@@ -104,6 +104,20 @@ return function render() {
}"
`;
exports[`compiler: v-for codegen template v-for w/ <slot/> 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, renderSlot: _renderSlot, openBlock: _openBlock, createBlock: _createBlock } = _Vue
return _createVNode(_Fragment, null, _renderList(items, (item) => {
return (_openBlock(), _createBlock(_Fragment, null, _renderSlot($slots.default)))
}), 128 /* UNKEYED_FRAGMENT */)
}
}"
`;
exports[`compiler: v-for codegen v-if + v-for 1`] = `
"const _Vue = Vue

View File

@@ -32,6 +32,20 @@ return function render() {
}"
`;
exports[`compiler: v-if codegen template v-if w/ single <slot/> child 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { openBlock: _openBlock, renderSlot: _renderSlot, Fragment: _Fragment, createBlock: _createBlock, Empty: _Empty } = _Vue
return (_openBlock(), ok
? _createBlock(_Fragment, { key: 0 }, _renderSlot($slots.default))
: _createBlock(_Empty))
}
}"
`;
exports[`compiler: v-if codegen v-if + v-else 1`] = `
"const _Vue = Vue
@@ -57,7 +71,9 @@ return function render() {
? _createBlock(\\"div\\", { key: 0 })
: orNot
? _createBlock(\\"p\\", { key: 1 })
: _createBlock(_Fragment, { key: 2 }, \\"fine\\"))
: _createBlock(_Fragment, { key: 2 }, [
\\"fine\\"
]))
}
}"
`;

View File

@@ -4,6 +4,7 @@ import { transformIf } from '../../src/transforms/vIf'
import { transformFor } from '../../src/transforms/vFor'
import { transformBind } from '../../src/transforms/vBind'
import { transformElement } from '../../src/transforms/transformElement'
import { transformSlotOutlet } from '../../src/transforms/transfromSlotOutlet'
import { transformExpression } from '../../src/transforms/transformExpression'
import {
ForNode,
@@ -20,7 +21,8 @@ import {
CREATE_BLOCK,
FRAGMENT,
RENDER_LIST,
CREATE_VNODE
CREATE_VNODE,
RENDER_SLOT
} from '../../src/runtimeConstants'
import { PatchFlags } from '@vue/runtime-dom'
import { PatchFlagNames } from '@vue/shared'
@@ -36,6 +38,7 @@ function parseWithForTransform(
transformIf,
transformFor,
...(options.prefixIdentifiers ? [transformExpression] : []),
transformSlotOutlet,
transformElement
],
directiveTransforms: {
@@ -692,6 +695,28 @@ describe('compiler: v-for', () => {
expect(generate(root).code).toMatchSnapshot()
})
test('template v-for w/ <slot/>', () => {
const {
root,
node: { codegenNode }
} = parseWithForTransform(
'<template v-for="item in items"><slot/></template>'
)
expect(assertSharedCodegen(codegenNode)).toMatchObject({
source: { content: `items` },
params: [{ content: `item` }],
blockArgs: [
`_${FRAGMENT}`,
`null`,
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: `_${RENDER_SLOT}`
}
]
})
expect(generate(root).code).toMatchSnapshot()
})
test('keyed v-for', () => {
const {
root,

View File

@@ -2,6 +2,7 @@ import { parse } from '../../src/parse'
import { transform } from '../../src/transform'
import { transformIf } from '../../src/transforms/vIf'
import { transformElement } from '../../src/transforms/transformElement'
import { transformSlotOutlet } from '../../src/transforms/transfromSlotOutlet'
import {
IfNode,
NodeTypes,
@@ -21,7 +22,8 @@ import {
EMPTY,
FRAGMENT,
MERGE_PROPS,
APPLY_DIRECTIVES
APPLY_DIRECTIVES,
RENDER_SLOT
} from '../../src/runtimeConstants'
import { createObjectMatcher } from '../testUtils'
@@ -32,7 +34,7 @@ function parseWithIfTransform(
) {
const ast = parse(template, options)
transform(ast, {
nodeTransforms: [transformIf, transformElement],
nodeTransforms: [transformIf, transformSlotOutlet, transformElement],
...options
})
if (!options.onError) {
@@ -344,6 +346,25 @@ describe('compiler: v-if', () => {
expect(generate(root).code).toMatchSnapshot()
})
test('template v-if w/ single <slot/> child', () => {
const {
root,
node: { codegenNode }
} = parseWithIfTransform(`<template v-if="ok"><slot/></template>`)
assertSharedCodegen(codegenNode)
const branch1 = (codegenNode.expressions[1] as ConditionalExpression)
.consequent as CallExpression
expect(branch1.arguments).toMatchObject([
`_${FRAGMENT}`,
`{ key: 0 }`,
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: `_${RENDER_SLOT}`
}
])
expect(generate(root).code).toMatchSnapshot()
})
test('v-if + v-else', () => {
const {
root,