mirror of https://github.com/vuejs/core.git
fix(compiler-vapor): don't generate default slot for whitespace when preserved (#13009)
This commit is contained in:
parent
6f8ea357b2
commit
cb925112f5
|
@ -274,3 +274,68 @@ export function render(_ctx) {
|
||||||
return n6
|
return n6
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: transform slot > with whitespace: 'preserve' > implicit default slot 1`] = `
|
||||||
|
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
|
||||||
|
const t0 = _template(" Header ")
|
||||||
|
const t1 = _template(" ")
|
||||||
|
const t2 = _template("<p></p>")
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const _component_Comp = _resolveComponent("Comp")
|
||||||
|
const n4 = _createComponentWithFallback(_component_Comp, null, {
|
||||||
|
"header": () => {
|
||||||
|
const n0 = t0()
|
||||||
|
return n0
|
||||||
|
},
|
||||||
|
"default": () => {
|
||||||
|
const n2 = t1()
|
||||||
|
const n3 = t2()
|
||||||
|
return [n2, n3]
|
||||||
|
}
|
||||||
|
}, true)
|
||||||
|
return n4
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: transform slot > with whitespace: 'preserve' > named default slot + implicit whitespace content 1`] = `
|
||||||
|
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
|
||||||
|
const t0 = _template(" Header ")
|
||||||
|
const t1 = _template(" Default ")
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const _component_Comp = _resolveComponent("Comp")
|
||||||
|
const n5 = _createComponentWithFallback(_component_Comp, null, {
|
||||||
|
"header": () => {
|
||||||
|
const n0 = t0()
|
||||||
|
return n0
|
||||||
|
},
|
||||||
|
"default": () => {
|
||||||
|
const n3 = t1()
|
||||||
|
return n3
|
||||||
|
}
|
||||||
|
}, true)
|
||||||
|
return n5
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: transform slot > with whitespace: 'preserve' > should not generate whitespace only default slot 1`] = `
|
||||||
|
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
|
||||||
|
const t0 = _template(" Header ")
|
||||||
|
const t1 = _template(" Footer ")
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const _component_Comp = _resolveComponent("Comp")
|
||||||
|
const n5 = _createComponentWithFallback(_component_Comp, null, {
|
||||||
|
"header": () => {
|
||||||
|
const n0 = t0()
|
||||||
|
return n0
|
||||||
|
},
|
||||||
|
"footer": () => {
|
||||||
|
const n3 = t1()
|
||||||
|
return n3
|
||||||
|
}
|
||||||
|
}, true)
|
||||||
|
return n5
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
|
@ -509,4 +509,60 @@ describe('compiler: transform slot', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe(`with whitespace: 'preserve'`, () => {
|
||||||
|
test('named default slot + implicit whitespace content', () => {
|
||||||
|
const source = `
|
||||||
|
<Comp>
|
||||||
|
<template #header> Header </template>
|
||||||
|
<template #default> Default </template>
|
||||||
|
</Comp>
|
||||||
|
`
|
||||||
|
const { code } = compileWithSlots(source, {
|
||||||
|
whitespace: 'preserve',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
`Extraneous children found when component already has explicitly named default slot.`,
|
||||||
|
).not.toHaveBeenWarned()
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('implicit default slot', () => {
|
||||||
|
const source = `
|
||||||
|
<Comp>
|
||||||
|
<template #header> Header </template>
|
||||||
|
<p/>
|
||||||
|
</Comp>
|
||||||
|
`
|
||||||
|
const { code } = compileWithSlots(source, {
|
||||||
|
whitespace: 'preserve',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
`Extraneous children found when component already has explicitly named default slot.`,
|
||||||
|
).not.toHaveBeenWarned()
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should not generate whitespace only default slot', () => {
|
||||||
|
const source = `
|
||||||
|
<Comp>
|
||||||
|
<template #header> Header </template>
|
||||||
|
<template #footer> Footer </template>
|
||||||
|
</Comp>
|
||||||
|
`
|
||||||
|
const { code, ir } = compileWithSlots(source, {
|
||||||
|
whitespace: 'preserve',
|
||||||
|
})
|
||||||
|
|
||||||
|
const slots = (ir.block.dynamic.children[0].operation as any).slots[0]
|
||||||
|
.slots
|
||||||
|
// should be: header, footer (no default)
|
||||||
|
expect(Object.keys(slots).length).toBe(2)
|
||||||
|
expect(!!slots['default']).toBe(false)
|
||||||
|
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -23,6 +23,13 @@ const seen = new WeakMap<
|
||||||
WeakSet<TemplateChildNode | RootNode>
|
WeakSet<TemplateChildNode | RootNode>
|
||||||
>()
|
>()
|
||||||
|
|
||||||
|
export function markNonTemplate(
|
||||||
|
node: TemplateChildNode,
|
||||||
|
context: TransformContext,
|
||||||
|
): void {
|
||||||
|
seen.get(context.root)!.add(node)
|
||||||
|
}
|
||||||
|
|
||||||
export const transformText: NodeTransform = (node, context) => {
|
export const transformText: NodeTransform = (node, context) => {
|
||||||
if (!seen.has(context.root)) seen.set(context.root, new WeakSet())
|
if (!seen.has(context.root)) seen.set(context.root, new WeakSet())
|
||||||
if (seen.get(context.root)!.has(node)) {
|
if (seen.get(context.root)!.has(node)) {
|
||||||
|
@ -68,7 +75,7 @@ export const transformText: NodeTransform = (node, context) => {
|
||||||
prev.type === NodeTypes.TEXT
|
prev.type === NodeTypes.TEXT
|
||||||
) {
|
) {
|
||||||
// mark leading text node for skipping
|
// mark leading text node for skipping
|
||||||
seen.get(context.root)!.add(prev)
|
markNonTemplate(prev, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +150,7 @@ function processTextContainer(
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTextLikeExpression(node: TextLike, context: TransformContext) {
|
function createTextLikeExpression(node: TextLike, context: TransformContext) {
|
||||||
seen.get(context.root)!.add(node)
|
markNonTemplate(node, context)
|
||||||
if (node.type === NodeTypes.TEXT) {
|
if (node.type === NodeTypes.TEXT) {
|
||||||
return createSimpleExpression(node.content, true, node.loc)
|
return createSimpleExpression(node.content, true, node.loc)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import {
|
||||||
type VaporDirectiveNode,
|
type VaporDirectiveNode,
|
||||||
} from '../ir'
|
} from '../ir'
|
||||||
import { findDir, resolveExpression } from '../utils'
|
import { findDir, resolveExpression } from '../utils'
|
||||||
|
import { markNonTemplate } from './transformText'
|
||||||
|
|
||||||
export const transformVSlot: NodeTransform = (node, context) => {
|
export const transformVSlot: NodeTransform = (node, context) => {
|
||||||
if (node.type !== NodeTypes.ELEMENT) return
|
if (node.type !== NodeTypes.ELEMENT) return
|
||||||
|
@ -66,11 +67,21 @@ function transformComponentSlot(
|
||||||
) {
|
) {
|
||||||
const { children } = node
|
const { children } = node
|
||||||
const arg = dir && dir.arg
|
const arg = dir && dir.arg
|
||||||
const nonSlotTemplateChildren = children.filter(
|
|
||||||
n =>
|
// whitespace: 'preserve'
|
||||||
isNonWhitespaceContent(node) &&
|
const emptyTextNodes: TemplateChildNode[] = []
|
||||||
!(n.type === NodeTypes.ELEMENT && n.props.some(isVSlot)),
|
const nonSlotTemplateChildren = children.filter(n => {
|
||||||
)
|
if (isNonWhitespaceContent(n)) {
|
||||||
|
return !(n.type === NodeTypes.ELEMENT && n.props.some(isVSlot))
|
||||||
|
} else {
|
||||||
|
emptyTextNodes.push(n)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!nonSlotTemplateChildren.length) {
|
||||||
|
emptyTextNodes.forEach(n => {
|
||||||
|
markNonTemplate(n, context)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const [block, onExit] = createSlotBlock(node, dir, context)
|
const [block, onExit] = createSlotBlock(node, dir, context)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue