]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(ssr): fix scopeId inheritance across mixed parent chain
authorEvan You <yyx990803@gmail.com>
Tue, 30 Mar 2021 22:39:42 +0000 (18:39 -0400)
committerEvan You <yyx990803@gmail.com>
Tue, 30 Mar 2021 22:39:42 +0000 (18:39 -0400)
fix #3513

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

index 7726739e4012d1c008cb77e9b8c7ce3422551b5e..3091153e1e62a803ecb4784921197fc334fb581e 100644 (file)
@@ -1,4 +1,4 @@
-import { createApp, mergeProps, withCtx } from 'vue'
+import { createApp, h, mergeProps, withCtx } from 'vue'
 import { renderToString } from '../src/renderToString'
 import { ssrRenderComponent, ssrRenderAttrs, ssrRenderSlot } from '../src'
 
@@ -154,4 +154,29 @@ describe('ssr: scopedId runtime behavior', () => {
         `</div>`
     )
   })
+
+  // #3513
+  test('scopeId inheritance across ssr-compiled andn on-ssr compiled parent chain', async () => {
+    const Child = {
+      ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
+        push(`<div${ssrRenderAttrs(attrs)}></div>`)
+      }
+    }
+
+    const Middle = {
+      render() {
+        return h(Child)
+      }
+    }
+
+    const Comp = {
+      __scopeId: 'parent',
+      ssrRender: (ctx: any, push: any, parent: any) => {
+        push(ssrRenderComponent(Middle, null, null, parent))
+      }
+    }
+
+    const result = await renderToString(createApp(Comp)) // output: `<div></div>`
+    expect(result).toBe(`<div parent></div>`)
+  })
 })
index 4f20e52e3f8ec55e24744bf377673a61df57b7ce..b3002ab2acfaead7126e0472c07bbc5940f7b0fa 100644 (file)
@@ -129,13 +129,31 @@ function renderComponentSubTree(
       // resolve fallthrough attrs
       let attrs =
         instance.type.inheritAttrs !== false ? instance.attrs : undefined
+      let hasCloned = false
 
-      // inherited scopeId
-      const scopeId = instance.vnode.scopeId
-      if (scopeId || slotScopeId) {
-        attrs = { ...attrs }
-        if (scopeId) attrs[scopeId] = ''
-        if (slotScopeId) attrs[slotScopeId.trim()] = ''
+      let cur = instance
+      while (true) {
+        const scopeId = cur.vnode.scopeId
+        if (scopeId) {
+          if (!hasCloned) {
+            attrs = { ...attrs }
+            hasCloned = true
+          }
+          attrs![scopeId] = ''
+        }
+        const parent = cur.parent
+        if (parent && parent.subTree && parent.subTree === cur.vnode) {
+          // parent is a non-SSR compiled component and is rendering this
+          // component as root. inherit its scopeId if present.
+          cur = parent
+        } else {
+          break
+        }
+      }
+
+      if (slotScopeId) {
+        if (!hasCloned) attrs = { ...attrs }
+        attrs![slotScopeId.trim()] = ''
       }
 
       // set current rendering instance for asset resolution