diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap
index 0c8e061f9ef..7c8837dd6b3 100644
--- a/packages/compiler-core/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap
+++ b/packages/compiler-core/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap
@@ -215,6 +215,34 @@ return function render(_ctx, _cache) {
}"
`;
+exports[`compiler: transform component slots > template named v-if/else and whitespace preserve 1`] = `
+"const { toDisplayString: _toDisplayString, createTextVNode: _createTextVNode, resolveComponent: _resolveComponent, withCtx: _withCtx, createSlots: _createSlots, openBlock: _openBlock, createBlock: _createBlock } = Vue
+
+return function render(_ctx, _cache) {
+ const _component_Comp = _resolveComponent(\\"Comp\\")
+
+ return (_openBlock(), _createBlock(_component_Comp, null, _createSlots({ _: 2 /* DYNAMIC */ }, [
+ true
+ ? {
+ name: \\"one\\",
+ fn: _withCtx(() => [
+ _createTextVNode(_toDisplayString(_ctx.foo) + _toDisplayString(_ctx.bar), 1 /* TEXT */)
+ ]),
+ key: \\"0\\"
+ }
+ : true
+ ? {
+ name: \\"one\\",
+ fn: _withCtx(() => [
+ _createTextVNode(_toDisplayString(_ctx.foo) + _toDisplayString(_ctx.bar), 1 /* TEXT */)
+ ]),
+ key: \\"1\\"
+ }
+ : undefined
+ ]), 1024 /* DYNAMIC_SLOTS */))
+}"
+`;
+
exports[`compiler: transform component slots > with whitespace: 'preserve' > implicit default slot 1`] = `
"const { createElementVNode: _createElementVNode, resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = Vue
diff --git a/packages/compiler-core/__tests__/transforms/vSlot.spec.ts b/packages/compiler-core/__tests__/transforms/vSlot.spec.ts
index bb3d9d2cfa3..f9cc50dd6cf 100644
--- a/packages/compiler-core/__tests__/transforms/vSlot.spec.ts
+++ b/packages/compiler-core/__tests__/transforms/vSlot.spec.ts
@@ -28,8 +28,14 @@ import { createObjectMatcher, genFlagText } from '../testUtils'
import { PatchFlags } from '@vue/shared'
import { transformFor } from '../../src/transforms/vFor'
import { transformIf } from '../../src/transforms/vIf'
+import { transformText } from '../../src/transforms/transformText'
-function parseWithSlots(template: string, options: CompilerOptions = {}) {
+function parseWithSlots(
+ template: string,
+ options: CompilerOptions & {
+ appendNodeTransforms?: CompilerOptions['nodeTransforms']
+ } = {}
+) {
const ast = parse(template, {
whitespace: options.whitespace
})
@@ -42,7 +48,8 @@ function parseWithSlots(template: string, options: CompilerOptions = {}) {
: []),
transformSlotOutlet,
transformElement,
- trackSlotScopes
+ trackSlotScopes,
+ ...(options.appendNodeTransforms ?? [])
],
directiveTransforms: {
on: transformOn,
@@ -234,6 +241,27 @@ describe('compiler: transform component slots', () => {
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
+ // #6063 should not throw error
+ test('template named v-if/else and whitespace preserve', () => {
+ const { root } = parseWithSlots(
+ `
+
+ {{ foo }}{{ bar }}
+
+
+ {{ foo }}{{ bar }}
+
+ `,
+ {
+ whitespace: 'preserve',
+ prefixIdentifiers: true,
+ appendNodeTransforms: [transformText]
+ }
+ )
+
+ expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
+ })
+
test('on component dynamically named slot', () => {
const { root, slots } = parseWithSlots(
`{{ foo }}{{ bar }}`,
diff --git a/packages/compiler-core/src/transforms/vSlot.ts b/packages/compiler-core/src/transforms/vSlot.ts
index c4416dd45f7..ce71c8ff148 100644
--- a/packages/compiler-core/src/transforms/vSlot.ts
+++ b/packages/compiler-core/src/transforms/vSlot.ts
@@ -223,6 +223,13 @@ export function buildSlots(
let prev
while (j--) {
prev = children[j]
+ if (
+ prev.type === NodeTypes.TEXT_CALL &&
+ prev.content.type === NodeTypes.TEXT &&
+ prev.content.content === ' '
+ ) {
+ continue
+ }
if (prev.type !== NodeTypes.COMMENT) {
break
}