mirror of https://github.com/vuejs/core.git
fix(hydration): properly handle optimized mode during hydrate node (#10638)
close #10607
This commit is contained in:
parent
0cef65cee4
commit
2ec06fd6c8
|
@ -7,7 +7,10 @@ import {
|
|||
Teleport,
|
||||
Transition,
|
||||
type VNode,
|
||||
createBlock,
|
||||
createCommentVNode,
|
||||
createElementBlock,
|
||||
createElementVNode,
|
||||
createSSRApp,
|
||||
createStaticVNode,
|
||||
createTextVNode,
|
||||
|
@ -17,16 +20,19 @@ import {
|
|||
h,
|
||||
nextTick,
|
||||
onMounted,
|
||||
openBlock,
|
||||
ref,
|
||||
renderSlot,
|
||||
useCssVars,
|
||||
vModelCheckbox,
|
||||
vShow,
|
||||
withCtx,
|
||||
withDirectives,
|
||||
} from '@vue/runtime-dom'
|
||||
import { type SSRContext, renderToString } from '@vue/server-renderer'
|
||||
import { PatchFlags } from '@vue/shared'
|
||||
import { vShowOriginalDisplay } from '../../runtime-dom/src/directives/vShow'
|
||||
import { expect } from 'vitest'
|
||||
|
||||
function mountWithHydration(html: string, render: () => any) {
|
||||
const container = document.createElement('div')
|
||||
|
@ -1292,6 +1298,81 @@ describe('SSR hydration', () => {
|
|||
`)
|
||||
})
|
||||
|
||||
// #10607
|
||||
test('update component stable slot (prod + optimized mode)', async () => {
|
||||
__DEV__ = false
|
||||
const container = document.createElement('div')
|
||||
container.innerHTML = `<template><div show="false"><!--[--><div><div><!----></div></div><div>0</div><!--]--></div></template>`
|
||||
const Comp = {
|
||||
render(this: any) {
|
||||
return (
|
||||
openBlock(),
|
||||
createElementBlock('div', null, [renderSlot(this.$slots, 'default')])
|
||||
)
|
||||
},
|
||||
}
|
||||
const show = ref(false)
|
||||
const clicked = ref(false)
|
||||
|
||||
const Wrapper = {
|
||||
setup() {
|
||||
const items = ref<number[]>([])
|
||||
onMounted(() => {
|
||||
items.value = [1]
|
||||
})
|
||||
return () => {
|
||||
return (
|
||||
openBlock(),
|
||||
createBlock(Comp, null, {
|
||||
default: withCtx(() => [
|
||||
createElementVNode('div', null, [
|
||||
createElementVNode('div', null, [
|
||||
clicked.value
|
||||
? (openBlock(),
|
||||
createElementBlock('div', { key: 0 }, 'foo'))
|
||||
: createCommentVNode('v-if', true),
|
||||
]),
|
||||
]),
|
||||
createElementVNode(
|
||||
'div',
|
||||
null,
|
||||
items.value.length,
|
||||
1 /* TEXT */,
|
||||
),
|
||||
]),
|
||||
_: 1 /* STABLE */,
|
||||
})
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
createSSRApp({
|
||||
components: { Wrapper },
|
||||
data() {
|
||||
return { show }
|
||||
},
|
||||
template: `<Wrapper :show="show"/>`,
|
||||
}).mount(container)
|
||||
|
||||
await nextTick()
|
||||
expect(container.innerHTML).toBe(
|
||||
`<div show="false"><!--[--><div><div><!----></div></div><div>1</div><!--]--></div>`,
|
||||
)
|
||||
|
||||
show.value = true
|
||||
await nextTick()
|
||||
expect(async () => {
|
||||
clicked.value = true
|
||||
await nextTick()
|
||||
}).not.toThrow("Cannot read properties of null (reading 'insertBefore')")
|
||||
|
||||
await nextTick()
|
||||
expect(container.innerHTML).toBe(
|
||||
`<div show="true"><!--[--><div><div><div>foo</div></div></div><div>1</div><!--]--></div>`,
|
||||
)
|
||||
__DEV__ = true
|
||||
})
|
||||
|
||||
describe('mismatch handling', () => {
|
||||
test('text node', () => {
|
||||
const { container } = mountWithHydration(`foo`, () => 'bar')
|
||||
|
|
|
@ -120,6 +120,7 @@ export function createHydrationFunctions(
|
|||
slotScopeIds: string[] | null,
|
||||
optimized = false,
|
||||
): Node | null => {
|
||||
optimized = optimized || !!vnode.dynamicChildren
|
||||
const isFragmentStart = isComment(node) && node.data === '['
|
||||
const onMismatch = () =>
|
||||
handleMismatch(
|
||||
|
|
Loading…
Reference in New Issue