mirror of https://github.com/vuejs/core.git
fix(ssr): fix hydration mismatch for disabled teleport at component root (#9399)
close #6152
This commit is contained in:
parent
a8f663867b
commit
d8990fc618
|
@ -393,6 +393,28 @@ describe('SSR hydration', () => {
|
|||
)
|
||||
})
|
||||
|
||||
// #6152
|
||||
test('Teleport (disabled + as component root)', () => {
|
||||
const { container } = mountWithHydration(
|
||||
'<!--[--><div>Parent fragment</div><!--teleport start--><div>Teleport content</div><!--teleport end--><!--]-->',
|
||||
() => [
|
||||
h('div', 'Parent fragment'),
|
||||
h(() =>
|
||||
h(Teleport, { to: 'body', disabled: true }, [
|
||||
h('div', 'Teleport content')
|
||||
])
|
||||
)
|
||||
]
|
||||
)
|
||||
expect(document.body.innerHTML).toBe('')
|
||||
expect(container.innerHTML).toBe(
|
||||
'<!--[--><div>Parent fragment</div><!--teleport start--><div>Teleport content</div><!--teleport end--><!--]-->'
|
||||
)
|
||||
expect(
|
||||
`Hydration completed but contains mismatches.`
|
||||
).not.toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('Teleport (as component root)', () => {
|
||||
const teleportContainer = document.createElement('div')
|
||||
teleportContainer.id = 'teleport4'
|
||||
|
|
|
@ -227,20 +227,18 @@ 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
|
||||
? locateClosingAsyncAnchor(node)
|
||||
: nextSibling(node)
|
||||
|
||||
// #4293 teleport as component root
|
||||
if (
|
||||
nextNode &&
|
||||
isComment(nextNode) &&
|
||||
nextNode.data === 'teleport end'
|
||||
) {
|
||||
nextNode = nextSibling(nextNode)
|
||||
// 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
|
||||
|
@ -533,7 +531,7 @@ export function createHydrationFunctions(
|
|||
|
||||
if (isFragment) {
|
||||
// remove excessive fragment nodes
|
||||
const end = locateClosingAsyncAnchor(node)
|
||||
const end = locateClosingAnchor(node)
|
||||
while (true) {
|
||||
const next = nextSibling(node)
|
||||
if (next && next !== end) {
|
||||
|
@ -561,13 +559,18 @@ export function createHydrationFunctions(
|
|||
return next
|
||||
}
|
||||
|
||||
const locateClosingAsyncAnchor = (node: Node | null): Node | null => {
|
||||
// looks ahead for a start and closing comment node
|
||||
const locateClosingAnchor = (
|
||||
node: Node | null,
|
||||
open = '[',
|
||||
close = ']'
|
||||
): Node | null => {
|
||||
let match = 0
|
||||
while (node) {
|
||||
node = nextSibling(node)
|
||||
if (node && isComment(node)) {
|
||||
if (node.data === '[') match++
|
||||
if (node.data === ']') {
|
||||
if (node.data === open) match++
|
||||
if (node.data === close) {
|
||||
if (match === 0) {
|
||||
return nextSibling(node)
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue