From f4d2c9fc6afea827a081c1eeab78ce5c0cc620ca Mon Sep 17 00:00:00 2001 From: edison Date: Wed, 13 Apr 2022 17:58:29 +0800 Subject: [PATCH] fix(custom-elements): work with async component + slots (#4657) close #4639 --- .../runtime-core/src/helpers/renderSlot.ts | 11 ++++++-- .../__tests__/customElement.spec.ts | 28 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/helpers/renderSlot.ts b/packages/runtime-core/src/helpers/renderSlot.ts index 9389cc28abe..9310ee0b8f4 100644 --- a/packages/runtime-core/src/helpers/renderSlot.ts +++ b/packages/runtime-core/src/helpers/renderSlot.ts @@ -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 `` @@ -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 }, diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index 777f9677d04..e29c36123f3 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -457,5 +457,33 @@ describe('defineCustomElement', () => { const e = container.childNodes[0] as VueElement expect(e.shadowRoot!.innerHTML).toBe(`
20,number
`) }) + + 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 = `hi` + + await new Promise(r => setTimeout(r)) + + const e = container.childNodes[0] as VueElement + expect(e.shadowRoot!.innerHTML).toBe( + `
fallback
` + ) + }) }) })