diff --git a/packages/runtime-core/__tests__/helpers/scopeId.spec.ts b/packages/runtime-core/__tests__/helpers/scopeId.spec.ts
index 08f7b1e7d..b14d3acbc 100644
--- a/packages/runtime-core/__tests__/helpers/scopeId.spec.ts
+++ b/packages/runtime-core/__tests__/helpers/scopeId.spec.ts
@@ -17,6 +17,27 @@ describe('scopeId runtime support', () => {
expect(serializeInner(root)).toBe(`
`)
})
+ test('should attach scopeId to components in parent component', () => {
+ const Child = {
+ __scopeId: 'child',
+ render: withChildId(() => {
+ return h('div')
+ })
+ }
+ const App = {
+ __scopeId: 'parent',
+ render: withParentId(() => {
+ return h('div', [h(Child)])
+ })
+ }
+
+ const root = nodeOps.createElement('div')
+ render(h(App), root)
+ expect(serializeInner(root)).toBe(
+ ``
+ )
+ })
+
test('should work on slots', () => {
const Child = {
__scopeId: 'child',
@@ -41,7 +62,7 @@ describe('scopeId runtime support', () => {
// - scopeId from parent
// - slotted scopeId (with `-s` postfix) from child (the tree owner)
expect(serializeInner(root)).toBe(
- ``
+ ``
)
})
})
diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts
index 145a3697c..6b3be6727 100644
--- a/packages/runtime-core/src/componentRenderUtils.ts
+++ b/packages/runtime-core/src/componentRenderUtils.ts
@@ -39,6 +39,7 @@ export function renderComponentRoot(
): VNode {
const {
type: Component,
+ parent,
vnode,
proxy,
withProxy,
@@ -102,6 +103,11 @@ export function renderComponentRoot(
if (vnodeHooks !== EMPTY_OBJ) {
result = cloneVNode(result, vnodeHooks)
}
+ // inherit scopeId
+ const parentScopeId = parent && parent.type.__scopeId
+ if (parentScopeId) {
+ result = cloneVNode(result, { [parentScopeId]: '' })
+ }
// inherit directives
if (vnode.dirs != null) {
if (__DEV__ && !isElementRoot(result)) {
@@ -127,6 +133,7 @@ export function renderComponentRoot(
result = createVNode(Comment)
}
currentRenderingInstance = null
+
return result
}
diff --git a/packages/server-renderer/__tests__/renderToString.spec.ts b/packages/server-renderer/__tests__/renderToString.spec.ts
index 2ac929ac1..c8bb79c87 100644
--- a/packages/server-renderer/__tests__/renderToString.spec.ts
+++ b/packages/server-renderer/__tests__/renderToString.spec.ts
@@ -562,7 +562,7 @@ describe('ssr: renderToString', () => {
}
expect(await renderToString(h(Parent))).toBe(
- `slot
`
+ `slot
`
)
})
})
diff --git a/packages/server-renderer/__tests__/ssrRenderAttrs.spec.ts b/packages/server-renderer/__tests__/ssrRenderAttrs.spec.ts
index 87521a49a..38ca843c4 100644
--- a/packages/server-renderer/__tests__/ssrRenderAttrs.spec.ts
+++ b/packages/server-renderer/__tests__/ssrRenderAttrs.spec.ts
@@ -26,6 +26,14 @@ describe('ssr: renderAttrs', () => {
).toBe(` id="foo" title="bar"`)
})
+ test('empty value attrs', () => {
+ expect(
+ ssrRenderAttrs({
+ 'data-v-abc': ''
+ })
+ ).toBe(` data-v-abc`)
+ })
+
test('escape attrs', () => {
expect(
ssrRenderAttrs({
diff --git a/packages/server-renderer/src/helpers/ssrRenderAttrs.ts b/packages/server-renderer/src/helpers/ssrRenderAttrs.ts
index ef07bac30..d17c0dd11 100644
--- a/packages/server-renderer/src/helpers/ssrRenderAttrs.ts
+++ b/packages/server-renderer/src/helpers/ssrRenderAttrs.ts
@@ -53,7 +53,9 @@ export function ssrRenderDynamicAttr(
if (isBooleanAttr(attrKey)) {
return value === false ? `` : ` ${attrKey}`
} else if (isSSRSafeAttrName(attrKey)) {
- return ` ${attrKey}="${escapeHtml(value)}"`
+ return value === ''
+ ? ` ${attrKey}`
+ : ` ${attrKey}="${escapeHtml(value)}"`
} else {
console.warn(
`[@vue/server-renderer] Skipped rendering unsafe attribute name: ${attrKey}`