Skip to content

Commit

Permalink
fix(hydration): fix tracking of reactive style objects in production
Browse files Browse the repository at this point in the history
close #11372
  • Loading branch information
yyx990803 committed Jul 17, 2024
1 parent a509e30 commit c10e40a
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
35 changes: 34 additions & 1 deletion packages/runtime-core/__tests__/hydration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
nextTick,
onMounted,
openBlock,
reactive,
ref,
renderSlot,
useCssVars,
Expand All @@ -31,7 +32,7 @@ import {
withDirectives,
} from '@vue/runtime-dom'
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 { expect } from 'vitest'

Expand Down Expand Up @@ -1196,6 +1197,38 @@ describe('SSR hydration', () => {
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 () => {
const container = document.createElement('DIV')
container.innerHTML = '<button></button>'
Expand Down
6 changes: 6 additions & 0 deletions packages/runtime-core/src/hydration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
} from './components/Suspense'
import type { TeleportImpl, TeleportVNode } from './components/Teleport'
import { isAsyncWrapper } from './apiAsyncComponent'
import { isReactive } from '@vue/reactivity'

export type RootHydrateFunction = (
vnode: VNode<Node, Element>,
Expand Down Expand Up @@ -487,6 +488,11 @@ export function createHydrationFunctions(
undefined,
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]
}
}

Expand Down

0 comments on commit c10e40a

Please sign in to comment.