diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts
index 34e76100ee4..c3976a8f076 100644
--- a/packages/runtime-core/__tests__/hydration.spec.ts
+++ b/packages/runtime-core/__tests__/hydration.spec.ts
@@ -922,7 +922,9 @@ describe('SSR hydration', () => {
])
}
}
- const { container, vnode } = mountWithHydration('', () => h(Comp))
+ const { container, vnode } = mountWithHydration('', () =>
+ h(Comp)
+ )
expect(container.childNodes.length).toBe(3)
const text = container.childNodes[1]
expect(text.nodeType).toBe(3)
@@ -931,6 +933,33 @@ describe('SSR hydration', () => {
expect((vnode as any).component?.subTree.children[0].el).toBe(text)
})
+ test('app.unmount()', async () => {
+ const container = document.createElement('DIV')
+ container.innerHTML = ''
+ const App = defineComponent({
+ setup(_, { expose }) {
+ const count = ref(0)
+
+ expose({ count })
+
+ return () =>
+ h('button', {
+ onClick: () => count.value++
+ })
+ }
+ })
+
+ const app = createSSRApp(App)
+ const vm = app.mount(container)
+ await nextTick()
+ expect((container as any)._vnode).toBeDefined()
+ // @ts-expect-error - expose()'d properties are not available on vm type
+ expect(vm.count).toBe(0)
+
+ app.unmount()
+ expect((container as any)._vnode).toBe(null)
+ })
+
describe('mismatch handling', () => {
test('text node', () => {
const { container } = mountWithHydration(`foo`, () => 'bar')
diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts
index 61644184dee..3637a09b2aa 100644
--- a/packages/runtime-core/src/hydration.ts
+++ b/packages/runtime-core/src/hydration.ts
@@ -27,7 +27,7 @@ import { isAsyncWrapper } from './apiAsyncComponent'
export type RootHydrateFunction = (
vnode: VNode,
- container: Element | ShadowRoot
+ container: (Element | ShadowRoot) & { _vnode?: VNode }
) => void
const enum DOMNodeTypes {
@@ -75,11 +75,13 @@ export function createHydrationFunctions(
)
patch(null, vnode, container)
flushPostFlushCbs()
+ container._vnode = vnode
return
}
hasMismatch = false
hydrateNode(container.firstChild!, vnode, null, null, null)
flushPostFlushCbs()
+ container._vnode = vnode
if (hasMismatch && !__TEST__) {
// this error should show up in production
console.error(`Hydration completed but contains mismatches.`)