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)', () => {
|
test('Teleport (as component root)', () => {
|
||||||
const teleportContainer = document.createElement('div')
|
const teleportContainer = document.createElement('div')
|
||||||
teleportContainer.id = 'teleport4'
|
teleportContainer.id = 'teleport4'
|
||||||
|
|
|
@ -227,20 +227,18 @@ export function createHydrationFunctions(
|
||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
|
|
||||||
// component may be async, so in the case of fragments we cannot rely
|
// Locate the next node.
|
||||||
// on component's rendered output to determine the end of the fragment
|
if (isFragmentStart) {
|
||||||
// instead, we do a lookahead to find the end anchor node.
|
// If it's a fragment: since components may be async, we cannot rely
|
||||||
nextNode = isFragmentStart
|
// on component's rendered output to determine the end of the
|
||||||
? locateClosingAsyncAnchor(node)
|
// fragment. Instead, we do a lookahead to find the end anchor node.
|
||||||
: nextSibling(node)
|
nextNode = locateClosingAnchor(node)
|
||||||
|
} else if (isComment(node) && node.data === 'teleport start') {
|
||||||
// #4293 teleport as component root
|
// #4293 #6152
|
||||||
if (
|
// If a teleport is at component root, look ahead for teleport end.
|
||||||
nextNode &&
|
nextNode = locateClosingAnchor(node, node.data, 'teleport end')
|
||||||
isComment(nextNode) &&
|
} else {
|
||||||
nextNode.data === 'teleport end'
|
nextNode = nextSibling(node)
|
||||||
) {
|
|
||||||
nextNode = nextSibling(nextNode)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #3787
|
// #3787
|
||||||
|
@ -533,7 +531,7 @@ export function createHydrationFunctions(
|
||||||
|
|
||||||
if (isFragment) {
|
if (isFragment) {
|
||||||
// remove excessive fragment nodes
|
// remove excessive fragment nodes
|
||||||
const end = locateClosingAsyncAnchor(node)
|
const end = locateClosingAnchor(node)
|
||||||
while (true) {
|
while (true) {
|
||||||
const next = nextSibling(node)
|
const next = nextSibling(node)
|
||||||
if (next && next !== end) {
|
if (next && next !== end) {
|
||||||
|
@ -561,13 +559,18 @@ export function createHydrationFunctions(
|
||||||
return next
|
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
|
let match = 0
|
||||||
while (node) {
|
while (node) {
|
||||||
node = nextSibling(node)
|
node = nextSibling(node)
|
||||||
if (node && isComment(node)) {
|
if (node && isComment(node)) {
|
||||||
if (node.data === '[') match++
|
if (node.data === open) match++
|
||||||
if (node.data === ']') {
|
if (node.data === close) {
|
||||||
if (match === 0) {
|
if (match === 0) {
|
||||||
return nextSibling(node)
|
return nextSibling(node)
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue