Skip to content

Commit 5e54081

Browse files
committed
fix(ssr): fix scopeId inheritance across mixed parent chain
fix #3513
1 parent 6cab91d commit 5e54081

File tree

2 files changed

+50
-7
lines changed

2 files changed

+50
-7
lines changed

packages/server-renderer/__tests__/ssrScopeId.spec.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createApp, mergeProps, withCtx } from 'vue'
1+
import { createApp, h, mergeProps, withCtx } from 'vue'
22
import { renderToString } from '../src/renderToString'
33
import { ssrRenderComponent, ssrRenderAttrs, ssrRenderSlot } from '../src'
44

@@ -154,4 +154,29 @@ describe('ssr: scopedId runtime behavior', () => {
154154
`</div>`
155155
)
156156
})
157+
158+
// #3513
159+
test('scopeId inheritance across ssr-compiled andn on-ssr compiled parent chain', async () => {
160+
const Child = {
161+
ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
162+
push(`<div${ssrRenderAttrs(attrs)}></div>`)
163+
}
164+
}
165+
166+
const Middle = {
167+
render() {
168+
return h(Child)
169+
}
170+
}
171+
172+
const Comp = {
173+
__scopeId: 'parent',
174+
ssrRender: (ctx: any, push: any, parent: any) => {
175+
push(ssrRenderComponent(Middle, null, null, parent))
176+
}
177+
}
178+
179+
const result = await renderToString(createApp(Comp)) // output: `<div></div>`
180+
expect(result).toBe(`<div parent></div>`)
181+
})
157182
})

packages/server-renderer/src/render.ts

+24-6
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,31 @@ function renderComponentSubTree(
129129
// resolve fallthrough attrs
130130
let attrs =
131131
instance.type.inheritAttrs !== false ? instance.attrs : undefined
132+
let hasCloned = false
132133

133-
// inherited scopeId
134-
const scopeId = instance.vnode.scopeId
135-
if (scopeId || slotScopeId) {
136-
attrs = { ...attrs }
137-
if (scopeId) attrs[scopeId] = ''
138-
if (slotScopeId) attrs[slotScopeId.trim()] = ''
134+
let cur = instance
135+
while (true) {
136+
const scopeId = cur.vnode.scopeId
137+
if (scopeId) {
138+
if (!hasCloned) {
139+
attrs = { ...attrs }
140+
hasCloned = true
141+
}
142+
attrs![scopeId] = ''
143+
}
144+
const parent = cur.parent
145+
if (parent && parent.subTree && parent.subTree === cur.vnode) {
146+
// parent is a non-SSR compiled component and is rendering this
147+
// component as root. inherit its scopeId if present.
148+
cur = parent
149+
} else {
150+
break
151+
}
152+
}
153+
154+
if (slotScopeId) {
155+
if (!hasCloned) attrs = { ...attrs }
156+
attrs![slotScopeId.trim()] = ''
139157
}
140158

141159
// set current rendering instance for asset resolution

0 commit comments

Comments
 (0)