From 45fc3eb74cec1bd7c04be13a623b151066b8df5b Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 16 Jun 2021 12:42:13 +0200 Subject: [PATCH 1/3] fix(warn): avoid warning on empty children with Suspense --- .../__tests__/components/Suspense.spec.ts | 74 +++++++++++++++++++ .../runtime-core/src/components/Suspense.ts | 7 +- packages/runtime-core/src/vnode.ts | 1 + 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index 065898048c3..544d8f50115 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -17,9 +17,12 @@ import { onUnmounted, onErrorCaptured, shallowRef, + SuspenseProps, + resolveDynamicComponent, Fragment } from '@vue/runtime-test' import { createApp, defineComponent } from 'vue' +import { RawSlots } from 'packages/runtime-core/src/componentSlots' describe('Suspense', () => { const deps: Promise[] = [] @@ -1523,4 +1526,75 @@ describe('Suspense', () => { expected = `
outerB
innerB
` expect(serializeInner(root)).toBe(expected) }) + + describe('warnings', () => { + // base function to check if a combination of solts warns or not + function baseCheckWarn( + sohuldWarn: boolean, + children: RawSlots, + props: SuspenseProps | null = null + ) { + const Comp = { + setup() { + return () => h(Suspense, props, children) + } + } + + const root = nodeOps.createElement('div') + render(h(Comp), root) + + if (sohuldWarn) { + expect(` slots expect a single root node.`).toHaveBeenWarned() + } else { + expect( + ` slots expect a single root node.` + ).not.toHaveBeenWarned() + } + } + + // actual function that we use in tests + const checkWarn = baseCheckWarn.bind(null, true) + const checkNoWarn = baseCheckWarn.bind(null, false) + + test('does not warn on single child', async () => { + checkNoWarn({ + default: h('div'), + fallback: h('div') + }) + }) + + test('does not warn on null', async () => { + checkNoWarn({ + default: null, + fallback: null + }) + }) + + test('does not warn on ', async () => { + checkNoWarn({ + default: () => [resolveDynamicComponent(null)] + // fallback: () => null + }) + }) + + test('does not warn on empty array', async () => { + checkNoWarn({ + default: [], + fallback: () => [] + }) + }) + + test('warns on multiple children in default', async () => { + checkWarn({ + default: [h('div'), h('div')] + }) + }) + + test('warns on multiple children in fallback', async () => { + checkWarn({ + default: h('div'), + fallback: [h('div'), h('div')] + }) + }) + }) }) diff --git a/packages/runtime-core/src/components/Suspense.ts b/packages/runtime-core/src/components/Suspense.ts index 3640733d734..ddf21dd2ed4 100644 --- a/packages/runtime-core/src/components/Suspense.ts +++ b/packages/runtime-core/src/components/Suspense.ts @@ -29,6 +29,7 @@ import { assertNumber } from '../warning' import { handleError, ErrorCodes } from '../errorHandling' +import { NULL_DYNAMIC_COMPONENT } from '../helpers/resolveAssets' export interface SuspenseProps { onResolve?: () => void @@ -795,7 +796,11 @@ function normalizeSuspenseSlot(s: any) { } if (isArray(s)) { const singleChild = filterSingleRoot(s) - if (__DEV__ && !singleChild) { + if ( + __DEV__ && + !singleChild && + s.filter(child => child !== NULL_DYNAMIC_COMPONENT).length > 0 + ) { warn(` slots expect a single root node.`) } s = singleChild diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index f8cf6652d31..10ee03c29c6 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -114,6 +114,7 @@ export type VNodeProps = { type VNodeChildAtom = | VNode + | typeof NULL_DYNAMIC_COMPONENT | string | number | boolean From a208a2a523d930471ff6dfbd3f8ce430c692564c Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 16 Jun 2021 14:23:05 +0200 Subject: [PATCH 2/3] refactor: typo --- packages/runtime-core/__tests__/components/Suspense.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index 544d8f50115..b2849570b8c 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -1530,7 +1530,7 @@ describe('Suspense', () => { describe('warnings', () => { // base function to check if a combination of solts warns or not function baseCheckWarn( - sohuldWarn: boolean, + shouldWarn: boolean, children: RawSlots, props: SuspenseProps | null = null ) { @@ -1543,7 +1543,7 @@ describe('Suspense', () => { const root = nodeOps.createElement('div') render(h(Comp), root) - if (sohuldWarn) { + if (shouldWarn) { expect(` slots expect a single root node.`).toHaveBeenWarned() } else { expect( From ed587e3220abf22799cafb8e7c9a4d7ff5384419 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Tue, 22 Jun 2021 17:26:31 +0200 Subject: [PATCH 3/3] chore: typos --- .../runtime-core/__tests__/components/Suspense.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index b2849570b8c..d822a992816 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -22,7 +22,7 @@ import { Fragment } from '@vue/runtime-test' import { createApp, defineComponent } from 'vue' -import { RawSlots } from 'packages/runtime-core/src/componentSlots' +import { type RawSlots } from 'packages/runtime-core/src/componentSlots' describe('Suspense', () => { const deps: Promise[] = [] @@ -1528,7 +1528,7 @@ describe('Suspense', () => { }) describe('warnings', () => { - // base function to check if a combination of solts warns or not + // base function to check if a combination of slots warns or not function baseCheckWarn( shouldWarn: boolean, children: RawSlots, @@ -1572,8 +1572,8 @@ describe('Suspense', () => { test('does not warn on ', async () => { checkNoWarn({ - default: () => [resolveDynamicComponent(null)] - // fallback: () => null + default: () => [resolveDynamicComponent(null)], + fallback: () => null }) })