mirror of https://github.com/vuejs/core.git
fix(hydration): fix tracking of reactive style objects in production
close #11372
This commit is contained in:
parent
a509e30f05
commit
c10e40a217
|
@ -22,6 +22,7 @@ import {
|
||||||
nextTick,
|
nextTick,
|
||||||
onMounted,
|
onMounted,
|
||||||
openBlock,
|
openBlock,
|
||||||
|
reactive,
|
||||||
ref,
|
ref,
|
||||||
renderSlot,
|
renderSlot,
|
||||||
useCssVars,
|
useCssVars,
|
||||||
|
@ -31,7 +32,7 @@ import {
|
||||||
withDirectives,
|
withDirectives,
|
||||||
} from '@vue/runtime-dom'
|
} from '@vue/runtime-dom'
|
||||||
import { type SSRContext, renderToString } from '@vue/server-renderer'
|
import { type SSRContext, renderToString } from '@vue/server-renderer'
|
||||||
import { PatchFlags } from '@vue/shared'
|
import { PatchFlags, normalizeStyle } from '@vue/shared'
|
||||||
import { vShowOriginalDisplay } from '../../runtime-dom/src/directives/vShow'
|
import { vShowOriginalDisplay } from '../../runtime-dom/src/directives/vShow'
|
||||||
import { expect } from 'vitest'
|
import { expect } from 'vitest'
|
||||||
|
|
||||||
|
@ -1196,6 +1197,38 @@ describe('SSR hydration', () => {
|
||||||
expect(text.nodeType).toBe(3)
|
expect(text.nodeType).toBe(3)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #11372
|
||||||
|
test('object style value tracking in prod', async () => {
|
||||||
|
__DEV__ = false
|
||||||
|
try {
|
||||||
|
const style = reactive({ color: 'red' })
|
||||||
|
const Comp = {
|
||||||
|
render(this: any) {
|
||||||
|
return (
|
||||||
|
openBlock(),
|
||||||
|
createElementBlock(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
style: normalizeStyle(style),
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
4 /* STYLE */,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const { container } = mountWithHydration(
|
||||||
|
`<div style="color: red;"></div>`,
|
||||||
|
() => h(Comp),
|
||||||
|
)
|
||||||
|
style.color = 'green'
|
||||||
|
await nextTick()
|
||||||
|
expect(container.innerHTML).toBe(`<div style="color: green;"></div>`)
|
||||||
|
} finally {
|
||||||
|
__DEV__ = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('app.unmount()', async () => {
|
test('app.unmount()', async () => {
|
||||||
const container = document.createElement('DIV')
|
const container = document.createElement('DIV')
|
||||||
container.innerHTML = '<button></button>'
|
container.innerHTML = '<button></button>'
|
||||||
|
|
|
@ -39,6 +39,7 @@ import {
|
||||||
} from './components/Suspense'
|
} from './components/Suspense'
|
||||||
import type { TeleportImpl, TeleportVNode } from './components/Teleport'
|
import type { TeleportImpl, TeleportVNode } from './components/Teleport'
|
||||||
import { isAsyncWrapper } from './apiAsyncComponent'
|
import { isAsyncWrapper } from './apiAsyncComponent'
|
||||||
|
import { isReactive } from '@vue/reactivity'
|
||||||
|
|
||||||
export type RootHydrateFunction = (
|
export type RootHydrateFunction = (
|
||||||
vnode: VNode<Node, Element>,
|
vnode: VNode<Node, Element>,
|
||||||
|
@ -487,6 +488,11 @@ export function createHydrationFunctions(
|
||||||
undefined,
|
undefined,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
)
|
)
|
||||||
|
} else if (patchFlag & PatchFlags.STYLE && isReactive(props.style)) {
|
||||||
|
// #11372: object style values are iterated during patch instead of
|
||||||
|
// render/normalization phase, but style patch is skipped during
|
||||||
|
// hydration, so we need to force iterate the object to track deps
|
||||||
|
for (const key in props.style) props.style[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue