From a1b491dfd4dbd9fdf8b2651aa54b3f7e90fd871b Mon Sep 17 00:00:00 2001 From: Evan You Date: Sat, 21 Oct 2023 11:30:04 +0800 Subject: [PATCH] refactor: tweaks --- .../runtime-core/__tests__/hydration.spec.ts | 46 +++++++++---------- packages/runtime-core/src/hydration.ts | 32 +++++++------ 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts index 2713fa4c5f4..f0a3a9333a7 100644 --- a/packages/runtime-core/__tests__/hydration.spec.ts +++ b/packages/runtime-core/__tests__/hydration.spec.ts @@ -393,6 +393,28 @@ describe('SSR hydration', () => { ) }) + // #6152 + test('Teleport (disabled + as component root)', () => { + const { container } = mountWithHydration( + '
Parent fragment
Teleport content
', + () => [ + h('div', 'Parent fragment'), + h(() => + h(Teleport, { to: 'body', disabled: true }, [ + h('div', 'Teleport content') + ]) + ) + ] + ) + expect(document.body.innerHTML).toBe('') + expect(container.innerHTML).toBe( + '
Parent fragment
Teleport content
' + ) + expect( + `Hydration completed but contains mismatches.` + ).not.toHaveBeenWarned() + }) + test('Teleport (as component root)', () => { const teleportContainer = document.createElement('div') teleportContainer.id = 'teleport4' @@ -1083,29 +1105,5 @@ describe('SSR hydration', () => { expect(teleportContainer.innerHTML).toBe(`value`) expect(`Hydration children mismatch`).toHaveBeenWarned() }) - // #6152 - test('Teleport is disabled', () => { - const { container } = mountWithHydration( - '
Parent fragment
Teleport content
', - () => [ - h('div', 'Parent fragment'), - h( - defineComponent( - () => () => - h(Teleport, { to: 'body', disabled: true }, [ - h('div', 'Teleport content') - ]) - ) - ) - ] - ) - expect(document.body.innerHTML).toBe('') - expect(container.innerHTML).toBe( - '
Parent fragment
Teleport content
' - ) - expect( - `Hydration completed but contains mismatches.` - ).not.toHaveBeenWarned() - }) }) }) diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts index 53fb718e595..097443dbc53 100644 --- a/packages/runtime-core/src/hydration.ts +++ b/packages/runtime-core/src/hydration.ts @@ -227,15 +227,19 @@ export function createHydrationFunctions( optimized ) - // component may be async, so in the case of fragments we cannot rely - // on component's rendered output to determine the end of the fragment - // instead, we do a lookahead to find the end anchor node. - nextNode = isFragmentStart - ? locateClosingAnchor(node, '[', ']') - : // #4293 #6152 if teleport start look ahead for teleport end. - isComment(node) && node.data === 'teleport start' - ? locateClosingAnchor(node, 'teleport start', 'teleport end') - : nextSibling(node) + // Locate the next node. + if (isFragmentStart) { + // If it's a fragment: since components may be async, we cannot rely + // on component's rendered output to determine the end of the + // fragment. Instead, we do a lookahead to find the end anchor node. + nextNode = locateClosingAnchor(node) + } else if (isComment(node) && node.data === 'teleport start') { + // #4293 #6152 + // If a teleport is at component root, look ahead for teleport end. + nextNode = locateClosingAnchor(node, node.data, 'teleport end') + } else { + nextNode = nextSibling(node) + } // #3787 // if component is async, it may get moved / unmounted before its @@ -527,7 +531,7 @@ export function createHydrationFunctions( if (isFragment) { // remove excessive fragment nodes - const end = locateClosingAnchor(node, '[', ']') + const end = locateClosingAnchor(node) while (true) { const next = nextSibling(node) if (next && next !== end) { @@ -558,15 +562,15 @@ export function createHydrationFunctions( // looks ahead for a start and closing comment node const locateClosingAnchor = ( node: Node | null, - startData: string, - endData: string + open = '[', + close = ']' ): Node | null => { let match = 0 while (node) { node = nextSibling(node) if (node && isComment(node)) { - if (node.data === startData) match++ - if (node.data === endData) { + if (node.data === open) match++ + if (node.data === close) { if (match === 0) { return nextSibling(node) } else {