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}`