Skip to content

Commit

Permalink
fix(hmr): fix the page not updating when using computed value as slot (
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangzhonghe committed Nov 17, 2022
1 parent f3e4f03 commit bf64137
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 15 deletions.
8 changes: 6 additions & 2 deletions packages/reactivity/src/computed.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DebuggerOptions, ReactiveEffect } from './effect'
import { Ref, trackRefValue, triggerRefValue } from './ref'
import { isFunction, NOOP } from '@vue/shared'
import { isFunction, isHmrUpdating, NOOP } from '@vue/shared'
import { ReactiveFlags, toRaw } from './reactive'
import { Dep } from './dep'

Expand Down Expand Up @@ -56,7 +56,11 @@ export class ComputedRefImpl<T> {
// the computed ref may get wrapped by other proxies e.g. readonly() #3376
const self = toRaw(this)
trackRefValue(self)
if (self._dirty || !self._cacheable) {
// #7155 - should return the latest value during HMR to avoid the page not updating.
if (__DEV__ && isHmrUpdating) {
self._dirty = false
self._value = self.effect.run()!
} else if (self._dirty || !self._cacheable) {
self._dirty = false
self._value = self.effect.run()!
}
Expand Down
31 changes: 31 additions & 0 deletions packages/runtime-core/__tests__/hmr.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,37 @@ describe('hot module replacement', () => {
expect(serializeInner(root)).toBe(`<div>bar</div>`)
})

// #7155 - should force update computed value when HMR is active
test('force update computed value', () => {
const root = nodeOps.createElement('div')
const parentId = 'test-force-computed-parent'
const childId = 'test-force-computed-child'

const Child: ComponentOptions = {
__hmrId: childId,
computed: {
slotContent() {
return this.$slots.default?.()
}
},
render: compileToFunction(`<component :is="() => slotContent" />`)
}
createRecord(childId, Child)

const Parent: ComponentOptions = {
__hmrId: parentId,
components: { Child },
render: compileToFunction(`<Child>1</Child>`)
}
createRecord(parentId, Parent)

render(h(Parent), root)
expect(serializeInner(root)).toBe(`1`)

rerender(parentId, compileToFunction(`<Child>2</Child>`))
expect(serializeInner(root)).toBe(`2`)
})

// #1305 - component should remove class
test('remove static class from parent', () => {
const root = nodeOps.createElement('div')
Expand Down
9 changes: 7 additions & 2 deletions packages/runtime-core/src/componentRenderUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ import {
blockStack
} from './vnode'
import { handleError, ErrorCodes } from './errorHandling'
import { PatchFlags, ShapeFlags, isOn, isModelListener } from '@vue/shared'
import {
PatchFlags,
ShapeFlags,
isOn,
isModelListener,
isHmrUpdating
} from '@vue/shared'
import { warn } from './warning'
import { isHmrUpdating } from './hmr'
import { NormalizedProps } from './componentProps'
import { isEmitListener } from './componentEmits'
import { setCurrentRenderingInstance } from './componentRenderContext'
Expand Down
4 changes: 2 additions & 2 deletions packages/runtime-core/src/componentSlots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import {
ShapeFlags,
extend,
def,
SlotFlags
SlotFlags,
isHmrUpdating
} from '@vue/shared'
import { warn } from './warning'
import { isKeepAlive } from './components/KeepAlive'
import { ContextualRenderFn, withCtx } from './componentRenderContext'
import { isHmrUpdating } from './hmr'
import { DeprecationTypes, isCompatEnabled } from './compat/compatConfig'
import { toRaw } from '@vue/reactivity'

Expand Down
3 changes: 1 addition & 2 deletions packages/runtime-core/src/components/Teleport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import {
traverseStaticChildren
} from '../renderer'
import { VNode, VNodeArrayChildren, VNodeProps } from '../vnode'
import { isString, ShapeFlags } from '@vue/shared'
import { isHmrUpdating, isString, ShapeFlags } from '@vue/shared'
import { warn } from '../warning'
import { isHmrUpdating } from '../hmr'

export type TeleportVNode = VNode<RendererNode, RendererElement, TeleportProps>

Expand Down
8 changes: 3 additions & 5 deletions packages/runtime-core/src/hmr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ import {
isClassComponent
} from './component'
import { queueJob, queuePostFlushCb } from './scheduler'
import { extend, getGlobalThis } from '@vue/shared'
import { extend, getGlobalThis, setHmrUpdating } from '@vue/shared'

type HMRComponent = ComponentOptions | ClassComponent

export let isHmrUpdating = false

export const hmrDirtyComponents = new Set<ConcreteComponent>()

export interface HMRRuntime {
Expand Down Expand Up @@ -92,9 +90,9 @@ function rerender(id: string, newRender?: Function) {
}
instance.renderCache = []
// this flag forces child components with slot content to update
isHmrUpdating = true
setHmrUpdating(true)
instance.update()
isHmrUpdating = false
setHmrUpdating(false)
})
}

Expand Down
5 changes: 3 additions & 2 deletions packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ import {
NOOP,
invokeArrayFns,
isArray,
getGlobalThis
getGlobalThis,
isHmrUpdating
} from '@vue/shared'
import {
queueJob,
Expand All @@ -58,7 +59,7 @@ import {
} from './components/Suspense'
import { TeleportImpl, TeleportVNode } from './components/Teleport'
import { isKeepAlive, KeepAliveContext } from './components/KeepAlive'
import { registerHMR, unregisterHMR, isHmrUpdating } from './hmr'
import { registerHMR, unregisterHMR } from './hmr'
import { createHydrationFunctions, RootHydrateFunction } from './hydration'
import { invokeDirectiveHook } from './directives'
import { startMeasure, endMeasure } from './profiling'
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/src/hmr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export let isHmrUpdating = false
export const setHmrUpdating = (v: boolean) => (isHmrUpdating = v)
1 change: 1 addition & 0 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export * from './escapeHtml'
export * from './looseEqual'
export * from './toDisplayString'
export * from './typeUtils'
export * from './hmr'

export const EMPTY_OBJ: { readonly [key: string]: any } = __DEV__
? Object.freeze({})
Expand Down

0 comments on commit bf64137

Please sign in to comment.