diff --git a/packages/runtime-core/__tests__/components/BaseTransition.spec.ts b/packages/runtime-core/__tests__/components/BaseTransition.spec.ts
index aaeae3fb4f0..b40113fb5b8 100644
--- a/packages/runtime-core/__tests__/components/BaseTransition.spec.ts
+++ b/packages/runtime-core/__tests__/components/BaseTransition.spec.ts
@@ -1198,4 +1198,51 @@ describe('BaseTransition', () => {
test('should not error on KeepAlive w/ function children', () => {
expect(() => mount({}, () => () => h('div'), true)).not.toThrow()
})
+
+ // #12465
+ test('mode: "out-in" w/ KeepAlive + fallthrough attrs (prod mode)', async () => {
+ __DEV__ = false
+ async function testOutIn({ trueBranch, falseBranch }: ToggleOptions) {
+ const toggle = ref(true)
+ const { props, cbs } = mockProps({ mode: 'out-in' }, true)
+ const root = nodeOps.createElement('div')
+ const App = {
+ render() {
+ return h(
+ BaseTransition,
+ {
+ ...props,
+ class: 'test',
+ },
+ () =>
+ h(KeepAlive, null, toggle.value ? trueBranch() : falseBranch()),
+ )
+ },
+ }
+ render(h(App), root)
+
+ expect(serializeInner(root)).toBe(`
0
`)
+
+ // trigger toggle
+ toggle.value = false
+ await nextTick()
+ expect(props.onBeforeLeave).toHaveBeenCalledTimes(1)
+ expect(serialize((props.onBeforeLeave as any).mock.calls[0][0])).toBe(
+ `0
`,
+ )
+ expect(props.onLeave).toHaveBeenCalledTimes(1)
+ expect(serialize((props.onLeave as any).mock.calls[0][0])).toBe(
+ `0
`,
+ )
+ expect(props.onAfterLeave).not.toHaveBeenCalled()
+ // enter should not have started
+ expect(props.onBeforeEnter).not.toHaveBeenCalled()
+ expect(props.onEnter).not.toHaveBeenCalled()
+ expect(props.onAfterEnter).not.toHaveBeenCalled()
+ cbs.doneLeave[`0
`]()
+ expect(serializeInner(root)).toBe(`0`)
+ }
+ await runTestWithKeepAlive(testOutIn)
+ __DEV__ = true
+ })
})
diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts
index 2b58bc3fc43..fbb449ec8cb 100644
--- a/packages/runtime-core/src/components/BaseTransition.ts
+++ b/packages/runtime-core/src/components/BaseTransition.ts
@@ -501,9 +501,8 @@ function getInnerChild(vnode: VNode): VNode | undefined {
return vnode
}
- // #7121 ensure get the child component subtree in case
- // it's been replaced during HMR
- if (__DEV__ && vnode.component) {
+ // #7121,#12465 get the component subtree if it's been mounted
+ if (vnode.component) {
return vnode.component.subTree
}