fix(ssr): fix hydration error for slot outlet inside transition
fix #3989
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { compile } from '../src'
|
||||
import { ssrHelpers, SSR_RENDER_SLOT_INNER } from '../src/runtimeHelpers'
|
||||
|
||||
describe('ssr: <slot>', () => {
|
||||
test('basic', () => {
|
||||
@@ -114,4 +115,16 @@ describe('ssr: <slot>', () => {
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
test('inside transition', () => {
|
||||
const { code } = compile(`<transition><slot/></transition>`)
|
||||
expect(code).toMatch(ssrHelpers[SSR_RENDER_SLOT_INNER])
|
||||
expect(code).toMatchInlineSnapshot(`
|
||||
"const { ssrRenderSlotInner: _ssrRenderSlotInner } = require(\\"vue/server-renderer\\")
|
||||
|
||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||
_ssrRenderSlotInner(_ctx.$slots, \\"default\\", {}, null, _push, _parent)
|
||||
}"
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@ export const SSR_INTERPOLATE = Symbol(`ssrInterpolate`)
|
||||
export const SSR_RENDER_VNODE = Symbol(`ssrRenderVNode`)
|
||||
export const SSR_RENDER_COMPONENT = Symbol(`ssrRenderComponent`)
|
||||
export const SSR_RENDER_SLOT = Symbol(`ssrRenderSlot`)
|
||||
export const SSR_RENDER_SLOT_INNER = Symbol(`ssrRenderSlotInner`)
|
||||
export const SSR_RENDER_CLASS = Symbol(`ssrRenderClass`)
|
||||
export const SSR_RENDER_STYLE = Symbol(`ssrRenderStyle`)
|
||||
export const SSR_RENDER_ATTRS = Symbol(`ssrRenderAttrs`)
|
||||
@@ -24,6 +25,7 @@ export const ssrHelpers = {
|
||||
[SSR_RENDER_VNODE]: `ssrRenderVNode`,
|
||||
[SSR_RENDER_COMPONENT]: `ssrRenderComponent`,
|
||||
[SSR_RENDER_SLOT]: `ssrRenderSlot`,
|
||||
[SSR_RENDER_SLOT_INNER]: `ssrRenderSlotInner`,
|
||||
[SSR_RENDER_CLASS]: `ssrRenderClass`,
|
||||
[SSR_RENDER_STYLE]: `ssrRenderStyle`,
|
||||
[SSR_RENDER_ATTRS]: `ssrRenderAttrs`,
|
||||
|
||||
@@ -4,9 +4,13 @@ import {
|
||||
processSlotOutlet,
|
||||
createCallExpression,
|
||||
SlotOutletNode,
|
||||
createFunctionExpression
|
||||
createFunctionExpression,
|
||||
NodeTypes,
|
||||
ElementTypes,
|
||||
resolveComponentType,
|
||||
TRANSITION
|
||||
} from '@vue/compiler-dom'
|
||||
import { SSR_RENDER_SLOT } from '../runtimeHelpers'
|
||||
import { SSR_RENDER_SLOT, SSR_RENDER_SLOT_INNER } from '../runtimeHelpers'
|
||||
import {
|
||||
SSRTransformContext,
|
||||
processChildrenAsStatement
|
||||
@@ -31,10 +35,24 @@ export const ssrTransformSlotOutlet: NodeTransform = (node, context) => {
|
||||
args.push(`"${context.scopeId}-s"`)
|
||||
}
|
||||
|
||||
node.ssrCodegenNode = createCallExpression(
|
||||
context.helper(SSR_RENDER_SLOT),
|
||||
args
|
||||
)
|
||||
let method = SSR_RENDER_SLOT
|
||||
|
||||
// #3989
|
||||
// check if this is a single slot inside a transition wrapper - since
|
||||
// transition will unwrap the slot fragment into a single vnode at runtime,
|
||||
// we need to avoid rendering the slot as a fragment.
|
||||
const parent = context.parent
|
||||
if (
|
||||
parent &&
|
||||
parent.type === NodeTypes.ELEMENT &&
|
||||
parent.tagType === ElementTypes.COMPONENT &&
|
||||
resolveComponentType(parent, context, true) === TRANSITION &&
|
||||
parent.children.filter(c => c.type === NodeTypes.ELEMENT).length === 1
|
||||
) {
|
||||
method = SSR_RENDER_SLOT_INNER
|
||||
}
|
||||
|
||||
node.ssrCodegenNode = createCallExpression(context.helper(method), args)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user