]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(custom-elements): work with async component + slots (#4657)
authoredison <daiwei521@126.com>
Wed, 13 Apr 2022 09:58:29 +0000 (17:58 +0800)
committerGitHub <noreply@github.com>
Wed, 13 Apr 2022 09:58:29 +0000 (05:58 -0400)
close #4639

packages/runtime-core/src/helpers/renderSlot.ts
packages/runtime-dom/__tests__/customElement.spec.ts

index 9389cc28abe73bd5849491bc84fd05ef37ec5d01..9310ee0b8f4e551e7a5ee6c27228719a140cdf81 100644 (file)
@@ -4,8 +4,9 @@ import {
   ContextualRenderFn,
   currentRenderingInstance
 } from '../componentRenderContext'
-import { Comment, isVNode } from '../vnode'
 import {
+  Comment,
+  isVNode,
   VNodeArrayChildren,
   openBlock,
   createBlock,
@@ -15,6 +16,7 @@ import {
 import { PatchFlags, SlotFlags } from '@vue/shared'
 import { warn } from '../warning'
 import { createVNode } from '@vue/runtime-core'
+import { isAsyncWrapper } from '../apiAsyncComponent'
 
 /**
  * Compiler runtime helper for rendering `<slot/>`
@@ -29,7 +31,12 @@ export function renderSlot(
   fallback?: () => VNodeArrayChildren,
   noSlotted?: boolean
 ): VNode {
-  if (currentRenderingInstance!.isCE) {
+  if (
+    currentRenderingInstance!.isCE ||
+    (currentRenderingInstance!.parent &&
+      isAsyncWrapper(currentRenderingInstance!.parent) &&
+      currentRenderingInstance!.parent.isCE)
+  ) {
     return createVNode(
       'slot',
       name === 'default' ? null : { name },
index 777f9677d048d61e0520e59aed577d6817f10f1a..e29c36123f316c8b7df6bf7b58bb8bca75c2c7ac 100644 (file)
@@ -457,5 +457,33 @@ describe('defineCustomElement', () => {
       const e = container.childNodes[0] as VueElement
       expect(e.shadowRoot!.innerHTML).toBe(`<div>20,number</div>`)
     })
+
+    test('with slots', async () => {
+      const E = defineCustomElement(
+        defineAsyncComponent(() => {
+          return Promise.resolve({
+            render(this: any) {
+              return [
+                h('div', null, [
+                  renderSlot(this.$slots, 'default', undefined, () => [
+                    h('div', 'fallback')
+                  ])
+                ]),
+                h('div', null, renderSlot(this.$slots, 'named'))
+              ]
+            }
+          })
+        })
+      )
+      customElements.define('my-el-async-slots', E)
+      container.innerHTML = `<my-el-async-slots><span>hi</span></my-el-async-slots>`
+
+      await new Promise(r => setTimeout(r))
+
+      const e = container.childNodes[0] as VueElement
+      expect(e.shadowRoot!.innerHTML).toBe(
+        `<div><slot><div>fallback</div></slot></div><div><slot name="named"></slot></div>`
+      )
+    })
   })
 })