diff --git a/packages/runtime-core/__tests__/helpers/scopeId.spec.ts b/packages/runtime-core/__tests__/helpers/scopeId.spec.ts
index 07ecfc7f..f570c7f0 100644
--- a/packages/runtime-core/__tests__/helpers/scopeId.spec.ts
+++ b/packages/runtime-core/__tests__/helpers/scopeId.spec.ts
@@ -34,7 +34,7 @@ describe('scopeId runtime support', () => {
const root = nodeOps.createElement('div')
render(h(App), root)
expect(serializeInner(root)).toBe(
- `
` +
+ `
` +
`
` +
// component inside slot should have:
// - scopeId from template context
// - slotted scopeId from slot owner
// - its own scopeId
- `
` +
+ `
` +
`
`
)
})
+
+ // #1988
+ test('should inherit scopeId through nested HOCs with inheritAttrs: false', () => {
+ const withParentId = withScopeId('parent')
+ const App = {
+ __scopeId: 'parent',
+ render: withParentId(() => {
+ return h(Child)
+ })
+ }
+
+ function Child() {
+ return h(Child2, { class: 'foo' })
+ }
+
+ function Child2() {
+ return h('div')
+ }
+ Child2.inheritAttrs = false
+
+ const root = nodeOps.createElement('div')
+ render(h(App), root)
+
+ expect(serializeInner(root)).toBe(`
`)
+ })
})
diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts
index 2c05358d..9c7ff21a 100644
--- a/packages/runtime-core/src/componentRenderUtils.ts
+++ b/packages/runtime-core/src/componentRenderUtils.ts
@@ -42,7 +42,6 @@ export function renderComponentRoot(
): VNode {
const {
type: Component,
- parent,
vnode,
proxy,
withProxy,
@@ -172,22 +171,6 @@ export function renderComponentRoot(
}
}
- // inherit scopeId
- const scopeId = vnode.scopeId
- // vite#536: if subtree root is created from parent slot if would already
- // have the correct scopeId, in this case adding the scopeId will cause
- // it to be removed if the original slot vnode is reused.
- const needScopeId = scopeId && root.scopeId !== scopeId
- const treeOwnerId = parent && parent.type.__scopeId
- const slotScopeId =
- treeOwnerId && treeOwnerId !== scopeId ? treeOwnerId + '-s' : null
- if (needScopeId || slotScopeId) {
- const extras: Data = {}
- if (needScopeId) extras[scopeId!] = ''
- if (slotScopeId) extras[slotScopeId] = ''
- root = cloneVNode(root, extras)
- }
-
// inherit directives
if (vnode.dirs) {
if (__DEV__ && !isElementRoot(root)) {
diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts
index cae1ffe5..9c69c6d4 100644
--- a/packages/runtime-core/src/renderer.ts
+++ b/packages/runtime-core/src/renderer.ts
@@ -745,15 +745,31 @@ function baseCreateRenderer(
}
}
// scopeId
- if (scopeId) {
- hostSetScopeId(el, scopeId)
- }
- const treeOwnerId = parentComponent && parentComponent.type.__scopeId
- // vnode's own scopeId and the current patched component's scopeId is
- // different - this is a slot content node.
- if (treeOwnerId && treeOwnerId !== scopeId) {
- hostSetScopeId(el, treeOwnerId + '-s')
- }
+ setScopeId(el, scopeId, vnode, parentComponent)
+ // if (scopeId) {
+ // hostSetScopeId(el, scopeId)
+ // }
+ // if (parentComponent) {
+ // const treeOwnerId = parentComponent.type.__scopeId
+ // // vnode's own scopeId and the current patched component's scopeId is
+ // // different - this is a slot content node.
+ // if (treeOwnerId && treeOwnerId !== scopeId) {
+ // hostSetScopeId(el, treeOwnerId + '-s')
+ // }
+ // const parentScopeId =
+ // vnode === parentComponent.subTree && parentComponent.vnode.scopeId
+ // if (parentScopeId) {
+ // hostSetScopeId(el, parentScopeId)
+ // if (parentComponent.parent) {
+ // const treeOwnerId = parentComponent.parent.type.__scopeId
+ // // vnode's own scopeId and the current patched component's scopeId is
+ // // different - this is a slot content node.
+ // if (treeOwnerId && treeOwnerId !== parentScopeId) {
+ // hostSetScopeId(el, treeOwnerId + '-s')
+ // }
+ // }
+ // }
+ // }
}
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
Object.defineProperty(el, '__vnode', {
@@ -791,6 +807,33 @@ function baseCreateRenderer(
}
}
+ const setScopeId = (
+ el: RendererElement,
+ scopeId: string | false | null,
+ vnode: VNode,
+ parentComponent: ComponentInternalInstance | null
+ ) => {
+ if (scopeId) {
+ hostSetScopeId(el, scopeId)
+ }
+ if (parentComponent) {
+ const treeOwnerId = parentComponent.type.__scopeId
+ // vnode's own scopeId and the current patched component's scopeId is
+ // different - this is a slot content node.
+ if (treeOwnerId && treeOwnerId !== scopeId) {
+ hostSetScopeId(el, treeOwnerId + '-s')
+ }
+ if (vnode === parentComponent.subTree) {
+ setScopeId(
+ el,
+ parentComponent.vnode.scopeId,
+ parentComponent.vnode,
+ parentComponent.parent
+ )
+ }
+ }
+ }
+
const mountChildren: MountChildrenFn = (
children,
container,
diff --git a/packages/server-renderer/__tests__/renderToStream.spec.ts b/packages/server-renderer/__tests__/renderToStream.spec.ts
index 5f7ecf67..4c9466b6 100644
--- a/packages/server-renderer/__tests__/renderToStream.spec.ts
+++ b/packages/server-renderer/__tests__/renderToStream.spec.ts
@@ -595,7 +595,7 @@ describe('ssr: renderToStream', () => {
}
expect(await renderToStream(h(Parent))).toBe(
- `
slot
`
+ `
slot
`
)
})
})
diff --git a/packages/server-renderer/__tests__/renderToString.spec.ts b/packages/server-renderer/__tests__/renderToString.spec.ts
index 3e2ff0cc..dfaab64c 100644
--- a/packages/server-renderer/__tests__/renderToString.spec.ts
+++ b/packages/server-renderer/__tests__/renderToString.spec.ts
@@ -551,7 +551,7 @@ describe('ssr: renderToString', () => {
}
expect(await renderToString(h(Parent))).toBe(
- `
slot
`
+ `
slot
`
)
})
})
diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts
index f8f9ac0b..0cb20625 100644
--- a/packages/server-renderer/src/render.ts
+++ b/packages/server-renderer/src/render.ts
@@ -101,7 +101,11 @@ function renderComponentSubTree(
const comp = instance.type as Component
const { getBuffer, push } = createBuffer()
if (isFunction(comp)) {
- renderVNode(push, renderComponentRoot(instance), instance)
+ renderVNode(
+ push,
+ (instance.subTree = renderComponentRoot(instance)),
+ instance
+ )
} else {
if (!instance.render && !comp.ssrRender && isString(comp.template)) {
comp.ssrRender = ssrCompile(comp.template, instance)
@@ -139,7 +143,11 @@ function renderComponentSubTree(
)
setCurrentRenderingInstance(null)
} else if (instance.render) {
- renderVNode(push, renderComponentRoot(instance), instance)
+ renderVNode(
+ push,
+ (instance.subTree = renderComponentRoot(instance)),
+ instance
+ )
} else {
warn(
`Component ${
@@ -225,15 +233,7 @@ function renderElementVNode(
openTag += ssrRenderAttrs(props, tag)
}
- if (scopeId) {
- openTag += ` ${scopeId}`
- const treeOwnerId = parentComponent && parentComponent.type.__scopeId
- // vnode's own scopeId and the current rendering component's scopeId is
- // different - this is a slot content node.
- if (treeOwnerId && treeOwnerId !== scopeId) {
- openTag += ` ${treeOwnerId}-s`
- }
- }
+ openTag += resolveScopeId(scopeId, vnode, parentComponent)
push(openTag + `>`)
if (!isVoidTag(tag)) {
@@ -265,6 +265,33 @@ function renderElementVNode(
}
}
+function resolveScopeId(
+ scopeId: string | null,
+ vnode: VNode,
+ parentComponent: ComponentInternalInstance | null
+) {
+ let res = ``
+ if (scopeId) {
+ res = ` ${scopeId}`
+ }
+ if (parentComponent) {
+ const treeOwnerId = parentComponent.type.__scopeId
+ // vnode's own scopeId and the current rendering component's scopeId is
+ // different - this is a slot content node.
+ if (treeOwnerId && treeOwnerId !== scopeId) {
+ res += ` ${treeOwnerId}-s`
+ }
+ if (vnode === parentComponent.subTree) {
+ res += resolveScopeId(
+ parentComponent.vnode.scopeId,
+ parentComponent.vnode,
+ parentComponent.parent
+ )
+ }
+ }
+ return res
+}
+
function applySSRDirectives(
vnode: VNode,
rawProps: VNodeProps | null,