fix(ssr): fix ssr scopeId on component root
This commit is contained in:
@@ -12,7 +12,7 @@ import {
|
||||
} from 'vue'
|
||||
import { escapeHtml, mockWarn } from '@vue/shared'
|
||||
import { renderToString } from '../src/renderToString'
|
||||
import { ssrRenderSlot } from '../src/helpers/ssrRenderSlot'
|
||||
import { ssrRenderSlot, SSRSlot } from '../src/helpers/ssrRenderSlot'
|
||||
import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent'
|
||||
|
||||
mockWarn()
|
||||
@@ -222,9 +222,9 @@ describe('ssr: renderToString', () => {
|
||||
{ msg: 'hello' },
|
||||
{
|
||||
// optimized slot using string push
|
||||
default: ({ msg }: any, push: any, _p: any) => {
|
||||
default: (({ msg }, push, _p) => {
|
||||
push(`<span>${msg}</span>`)
|
||||
},
|
||||
}) as SSRSlot,
|
||||
// important to avoid slots being normalized
|
||||
_: 1 as any
|
||||
},
|
||||
|
||||
62
packages/server-renderer/__tests__/ssrScopeId.spec.ts
Normal file
62
packages/server-renderer/__tests__/ssrScopeId.spec.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { createApp, withScopeId } from 'vue'
|
||||
import { renderToString } from '../src/renderToString'
|
||||
import { ssrRenderComponent, ssrRenderAttrs, ssrRenderSlot } from '../src'
|
||||
|
||||
describe('ssr: scoped id on component root', () => {
|
||||
test('basic', async () => {
|
||||
const withParentId = withScopeId('parent')
|
||||
|
||||
const Child = {
|
||||
ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
|
||||
push(`<div${ssrRenderAttrs(attrs)}></div>`)
|
||||
}
|
||||
}
|
||||
|
||||
const Comp = {
|
||||
ssrRender: withParentId((ctx: any, push: any, parent: any) => {
|
||||
push(ssrRenderComponent(Child), null, null, parent)
|
||||
})
|
||||
}
|
||||
|
||||
const result = await renderToString(createApp(Comp))
|
||||
expect(result).toBe(`<div parent></div>`)
|
||||
})
|
||||
|
||||
test('inside slot', async () => {
|
||||
const withParentId = withScopeId('parent')
|
||||
|
||||
const Child = {
|
||||
ssrRender: (_: any, push: any, _parent: any, attrs: any) => {
|
||||
push(`<div${ssrRenderAttrs(attrs)} child></div>`)
|
||||
}
|
||||
}
|
||||
|
||||
const Wrapper = {
|
||||
__scopeId: 'wrapper',
|
||||
ssrRender: (ctx: any, push: any, parent: any) => {
|
||||
ssrRenderSlot(ctx.$slots, 'default', {}, null, push, parent)
|
||||
}
|
||||
}
|
||||
|
||||
const Comp = {
|
||||
ssrRender: withParentId((_: any, push: any, parent: any) => {
|
||||
push(
|
||||
ssrRenderComponent(
|
||||
Wrapper,
|
||||
null,
|
||||
{
|
||||
default: withParentId((_: any, push: any, parent: any) => {
|
||||
push(ssrRenderComponent(Child, null, null, parent))
|
||||
}),
|
||||
_: 1
|
||||
} as any,
|
||||
parent
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const result = await renderToString(createApp(Comp))
|
||||
expect(result).toBe(`<!--[--><div parent wrapper-s child></div><!--]-->`)
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ComponentInternalInstance, Slot, Slots } from 'vue'
|
||||
import { ComponentInternalInstance, Slots } from 'vue'
|
||||
import { Props, PushFn, renderVNodeChildren } from '../render'
|
||||
|
||||
export type SSRSlots = Record<string, SSRSlot>
|
||||
@@ -21,13 +21,16 @@ export function ssrRenderSlot(
|
||||
push(`<!--[-->`)
|
||||
const slotFn = slots[slotName]
|
||||
if (slotFn) {
|
||||
if (slotFn.length > 1) {
|
||||
// only ssr-optimized slot fns accept more than 1 arguments
|
||||
const scopeId = parentComponent && parentComponent.type.__scopeId
|
||||
slotFn(slotProps, push, parentComponent, scopeId ? ` ${scopeId}-s` : ``)
|
||||
} else {
|
||||
const scopeId = parentComponent && parentComponent.type.__scopeId
|
||||
const ret = slotFn(
|
||||
slotProps,
|
||||
push,
|
||||
parentComponent,
|
||||
scopeId ? ` ${scopeId}-s` : ``
|
||||
)
|
||||
if (Array.isArray(ret)) {
|
||||
// normal slot
|
||||
renderVNodeChildren(push, (slotFn as Slot)(slotProps), parentComponent)
|
||||
renderVNodeChildren(push, ret, parentComponent)
|
||||
}
|
||||
} else if (fallbackRenderFn) {
|
||||
fallbackRenderFn()
|
||||
|
||||
@@ -109,11 +109,23 @@ function renderComponentSubTree(
|
||||
|
||||
if (comp.ssrRender) {
|
||||
// optimized
|
||||
// resolve fallthrough attrs
|
||||
let attrs =
|
||||
instance.type.inheritAttrs !== false ? instance.attrs : undefined
|
||||
|
||||
// inherited scopeId
|
||||
const scopeId = instance.vnode.scopeId
|
||||
const treeOwnerId = instance.parent && instance.parent.type.__scopeId
|
||||
const slotScopeId =
|
||||
treeOwnerId && treeOwnerId !== scopeId ? treeOwnerId + '-s' : null
|
||||
if (scopeId || slotScopeId) {
|
||||
attrs = { ...attrs }
|
||||
if (scopeId) attrs[scopeId] = ''
|
||||
if (slotScopeId) attrs[slotScopeId] = ''
|
||||
}
|
||||
|
||||
// set current rendering instance for asset resolution
|
||||
setCurrentRenderingInstance(instance)
|
||||
// fallthrough attrs
|
||||
const attrs =
|
||||
instance.type.inheritAttrs !== false ? instance.attrs : undefined
|
||||
comp.ssrRender(instance.proxy, push, instance, attrs)
|
||||
setCurrentRenderingInstance(null)
|
||||
} else if (instance.render) {
|
||||
|
||||
Reference in New Issue
Block a user