fix(sfc/scoped-style): inherit scopeId through nested HOCs with inheritAttrs: false
fix #1988
This commit is contained in:
parent
5b82c48c7b
commit
c0427b45ff
@ -34,7 +34,7 @@ describe('scopeId runtime support', () => {
|
|||||||
const root = nodeOps.createElement('div')
|
const root = nodeOps.createElement('div')
|
||||||
render(h(App), root)
|
render(h(App), root)
|
||||||
expect(serializeInner(root)).toBe(
|
expect(serializeInner(root)).toBe(
|
||||||
`<div parent><div parent child></div></div>`
|
`<div parent><div child parent></div></div>`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -67,14 +67,39 @@ describe('scopeId runtime support', () => {
|
|||||||
// - scopeId from parent
|
// - scopeId from parent
|
||||||
// - slotted scopeId (with `-s` postfix) from child (the tree owner)
|
// - slotted scopeId (with `-s` postfix) from child (the tree owner)
|
||||||
expect(serializeInner(root)).toBe(
|
expect(serializeInner(root)).toBe(
|
||||||
`<div parent child>` +
|
`<div child parent>` +
|
||||||
`<div parent child-s></div>` +
|
`<div parent child-s></div>` +
|
||||||
// component inside slot should have:
|
// component inside slot should have:
|
||||||
// - scopeId from template context
|
// - scopeId from template context
|
||||||
// - slotted scopeId from slot owner
|
// - slotted scopeId from slot owner
|
||||||
// - its own scopeId
|
// - its own scopeId
|
||||||
`<span parent child-s child2></span>` +
|
`<span child2 parent child-s></span>` +
|
||||||
`</div>`
|
`</div>`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #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(`<div parent></div>`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -42,7 +42,6 @@ export function renderComponentRoot(
|
|||||||
): VNode {
|
): VNode {
|
||||||
const {
|
const {
|
||||||
type: Component,
|
type: Component,
|
||||||
parent,
|
|
||||||
vnode,
|
vnode,
|
||||||
proxy,
|
proxy,
|
||||||
withProxy,
|
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
|
// inherit directives
|
||||||
if (vnode.dirs) {
|
if (vnode.dirs) {
|
||||||
if (__DEV__ && !isElementRoot(root)) {
|
if (__DEV__ && !isElementRoot(root)) {
|
||||||
|
@ -745,15 +745,31 @@ function baseCreateRenderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// scopeId
|
// scopeId
|
||||||
if (scopeId) {
|
setScopeId(el, scopeId, vnode, parentComponent)
|
||||||
hostSetScopeId(el, scopeId)
|
// if (scopeId) {
|
||||||
}
|
// hostSetScopeId(el, scopeId)
|
||||||
const treeOwnerId = parentComponent && parentComponent.type.__scopeId
|
// }
|
||||||
// vnode's own scopeId and the current patched component's scopeId is
|
// if (parentComponent) {
|
||||||
// different - this is a slot content node.
|
// const treeOwnerId = parentComponent.type.__scopeId
|
||||||
if (treeOwnerId && treeOwnerId !== scopeId) {
|
// // vnode's own scopeId and the current patched component's scopeId is
|
||||||
hostSetScopeId(el, treeOwnerId + '-s')
|
// // 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__) {
|
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
|
||||||
Object.defineProperty(el, '__vnode', {
|
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 = (
|
const mountChildren: MountChildrenFn = (
|
||||||
children,
|
children,
|
||||||
container,
|
container,
|
||||||
|
@ -595,7 +595,7 @@ describe('ssr: renderToStream', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expect(await renderToStream(h(Parent))).toBe(
|
expect(await renderToStream(h(Parent))).toBe(
|
||||||
`<div data-v-test data-v-child><span data-v-test data-v-child-s>slot</span></div>`
|
`<div data-v-child data-v-test><span data-v-test data-v-child-s>slot</span></div>`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -551,7 +551,7 @@ describe('ssr: renderToString', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expect(await renderToString(h(Parent))).toBe(
|
expect(await renderToString(h(Parent))).toBe(
|
||||||
`<div data-v-test data-v-child><span data-v-test data-v-child-s>slot</span></div>`
|
`<div data-v-child data-v-test><span data-v-test data-v-child-s>slot</span></div>`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -101,7 +101,11 @@ function renderComponentSubTree(
|
|||||||
const comp = instance.type as Component
|
const comp = instance.type as Component
|
||||||
const { getBuffer, push } = createBuffer()
|
const { getBuffer, push } = createBuffer()
|
||||||
if (isFunction(comp)) {
|
if (isFunction(comp)) {
|
||||||
renderVNode(push, renderComponentRoot(instance), instance)
|
renderVNode(
|
||||||
|
push,
|
||||||
|
(instance.subTree = renderComponentRoot(instance)),
|
||||||
|
instance
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
if (!instance.render && !comp.ssrRender && isString(comp.template)) {
|
if (!instance.render && !comp.ssrRender && isString(comp.template)) {
|
||||||
comp.ssrRender = ssrCompile(comp.template, instance)
|
comp.ssrRender = ssrCompile(comp.template, instance)
|
||||||
@ -139,7 +143,11 @@ function renderComponentSubTree(
|
|||||||
)
|
)
|
||||||
setCurrentRenderingInstance(null)
|
setCurrentRenderingInstance(null)
|
||||||
} else if (instance.render) {
|
} else if (instance.render) {
|
||||||
renderVNode(push, renderComponentRoot(instance), instance)
|
renderVNode(
|
||||||
|
push,
|
||||||
|
(instance.subTree = renderComponentRoot(instance)),
|
||||||
|
instance
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
warn(
|
warn(
|
||||||
`Component ${
|
`Component ${
|
||||||
@ -225,15 +233,7 @@ function renderElementVNode(
|
|||||||
openTag += ssrRenderAttrs(props, tag)
|
openTag += ssrRenderAttrs(props, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scopeId) {
|
openTag += resolveScopeId(scopeId, vnode, parentComponent)
|
||||||
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`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
push(openTag + `>`)
|
push(openTag + `>`)
|
||||||
if (!isVoidTag(tag)) {
|
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(
|
function applySSRDirectives(
|
||||||
vnode: VNode,
|
vnode: VNode,
|
||||||
rawProps: VNodeProps | null,
|
rawProps: VNodeProps | null,
|
||||||
|
Loading…
Reference in New Issue
Block a user