fix(compiler-core): fix whitespace management for slots with whitespace: 'preserve' (#3767)
fix #3766
This commit is contained in:
parent
f3d30363ec
commit
47da92146c
@ -209,3 +209,48 @@ return function render(_ctx, _cache) {
|
||||
}))
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: transform component slots with whitespace: 'preserve' implicit default slot 1`] = `
|
||||
"const { createVNode: _createVNode, resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = Vue
|
||||
|
||||
return function render(_ctx, _cache) {
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
return (_openBlock(), _createBlock(_component_Comp, null, {
|
||||
header: _withCtx(() => [\\" Header \\"]),
|
||||
default: _withCtx(() => [
|
||||
\\" \\",
|
||||
_createVNode(\\"p\\")
|
||||
]),
|
||||
_: 1 /* STABLE */
|
||||
}))
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: transform component slots with whitespace: 'preserve' named default slot + implicit whitespace content 1`] = `
|
||||
"const { resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = Vue
|
||||
|
||||
return function render(_ctx, _cache) {
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
return (_openBlock(), _createBlock(_component_Comp, null, {
|
||||
header: _withCtx(() => [\\" Header \\"]),
|
||||
default: _withCtx(() => [\\" Default \\"]),
|
||||
_: 1 /* STABLE */
|
||||
}))
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: transform component slots with whitespace: 'preserve' should not generate whitespace only default slot 1`] = `
|
||||
"const { resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = Vue
|
||||
|
||||
return function render(_ctx, _cache) {
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
return (_openBlock(), _createBlock(_component_Comp, null, {
|
||||
header: _withCtx(() => [\\" Header \\"]),
|
||||
footer: _withCtx(() => [\\" Footer \\"]),
|
||||
_: 1 /* STABLE */
|
||||
}))
|
||||
}"
|
||||
`;
|
||||
|
@ -9,7 +9,9 @@ import {
|
||||
ForNode,
|
||||
ComponentNode,
|
||||
VNodeCall,
|
||||
SlotsExpression
|
||||
SlotsExpression,
|
||||
ObjectExpression,
|
||||
SimpleExpressionNode
|
||||
} from '../../src'
|
||||
import { transformElement } from '../../src/transforms/transformElement'
|
||||
import { transformOn } from '../../src/transforms/vOn'
|
||||
@ -27,7 +29,9 @@ import { transformFor } from '../../src/transforms/vFor'
|
||||
import { transformIf } from '../../src/transforms/vIf'
|
||||
|
||||
function parseWithSlots(template: string, options: CompilerOptions = {}) {
|
||||
const ast = parse(template)
|
||||
const ast = parse(template, {
|
||||
whitespace: options.whitespace
|
||||
})
|
||||
transform(ast, {
|
||||
nodeTransforms: [
|
||||
transformIf,
|
||||
@ -862,4 +866,64 @@ describe('compiler: transform component slots', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe(`with whitespace: 'preserve'`, () => {
|
||||
test('named default slot + implicit whitespace content', () => {
|
||||
const source = `
|
||||
<Comp>
|
||||
<template #header> Header </template>
|
||||
<template #default> Default </template>
|
||||
</Comp>
|
||||
`
|
||||
const { root } = parseWithSlots(source, {
|
||||
whitespace: 'preserve'
|
||||
})
|
||||
|
||||
expect(
|
||||
`Extraneous children found when component already has explicitly named default slot.`
|
||||
).not.toHaveBeenWarned()
|
||||
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('implicit default slot', () => {
|
||||
const source = `
|
||||
<Comp>
|
||||
<template #header> Header </template>
|
||||
<p/>
|
||||
</Comp>
|
||||
`
|
||||
const { root } = parseWithSlots(source, {
|
||||
whitespace: 'preserve'
|
||||
})
|
||||
|
||||
expect(
|
||||
`Extraneous children found when component already has explicitly named default slot.`
|
||||
).not.toHaveBeenWarned()
|
||||
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should not generate whitespace only default slot', () => {
|
||||
const source = `
|
||||
<Comp>
|
||||
<template #header> Header </template>
|
||||
<template #footer> Footer </template>
|
||||
</Comp>
|
||||
`
|
||||
const { root } = parseWithSlots(source, {
|
||||
whitespace: 'preserve'
|
||||
})
|
||||
|
||||
// slots is vnodeCall's children as an ObjectExpression
|
||||
const slots = (root as any).children[0].codegenNode.children
|
||||
.properties as ObjectExpression['properties']
|
||||
|
||||
// should be: header, footer, _ (no default)
|
||||
expect(slots.length).toBe(3)
|
||||
expect(
|
||||
slots.some(p => (p.key as SimpleExpressionNode).content === 'default')
|
||||
).toBe(false)
|
||||
|
||||
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -311,7 +311,13 @@ export function buildSlots(
|
||||
if (!hasTemplateSlots) {
|
||||
// implicit default slot (on component)
|
||||
slotsProperties.push(buildDefaultSlotProperty(undefined, children))
|
||||
} else if (implicitDefaultChildren.length) {
|
||||
} else if (
|
||||
implicitDefaultChildren.length &&
|
||||
// #3766
|
||||
// with whitespace: 'preserve', whitespaces between slots will end up in
|
||||
// implicitDefaultChildren. Ignore if all implicit children are whitespaces.
|
||||
implicitDefaultChildren.some(node => isNonWhitespaceContent(node))
|
||||
) {
|
||||
// implicit default slot (mixed with named slots)
|
||||
if (hasNamedDefaultSlot) {
|
||||
context.onError(
|
||||
@ -397,3 +403,11 @@ function hasForwardedSlots(children: TemplateChildNode[]): boolean {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function isNonWhitespaceContent(node: TemplateChildNode): boolean {
|
||||
if (node.type !== NodeTypes.TEXT && node.type !== NodeTypes.TEXT_CALL)
|
||||
return true
|
||||
return node.type === NodeTypes.TEXT
|
||||
? !!node.content.trim()
|
||||
: isNonWhitespaceContent(node.content)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user