refactor(hmr): simplify hmr force update check

This commit is contained in:
Evan You 2020-06-12 14:53:48 -04:00
parent 8f2a7489b7
commit e76ed4c269
6 changed files with 24 additions and 43 deletions

View File

@ -71,10 +71,6 @@ export interface ComponentInternalOptions {
* @internal
*/
__hmrId?: string
/**
* @internal
*/
__hmrUpdated?: boolean
/**
* This one should be exposed so that devtools can make use of it
*/
@ -325,12 +321,6 @@ export interface ComponentInternalInstance {
* @internal
*/
[LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
/**
* hmr marker (dev only)
* @internal
*/
hmrUpdated?: boolean
}
const emptyAppContext = createAppContext()

View File

@ -16,6 +16,7 @@ import {
import { handleError, ErrorCodes } from './errorHandling'
import { PatchFlags, ShapeFlags, isOn } from '@vue/shared'
import { warn } from './warning'
import { isHmrUpdating } from './hmr'
// mark the current rendering instance for asset resolution (e.g.
// resolveComponent, resolveDirective) during render
@ -247,13 +248,8 @@ export function shouldUpdateComponent(
// Parent component's render function was hot-updated. Since this may have
// caused the child component's slots content to have changed, we need to
// force the child to update as well.
if (__DEV__ && (prevChildren || nextChildren) && parentComponent) {
let parent: ComponentInternalInstance | null = parentComponent
do {
if (parent.hmrUpdated) {
return true
}
} while ((parent = parent.parent))
if (__DEV__ && (prevChildren || nextChildren) && isHmrUpdating) {
return true
}
// force child update for runtime directive or transition on component vnode.

View File

@ -18,7 +18,7 @@ import {
import { warn } from './warning'
import { isKeepAlive } from './components/KeepAlive'
import { withCtx } from './helpers/withRenderContext'
import { queuePostFlushCb } from './scheduler'
import { isHmrUpdating } from './hmr'
export type Slot = (...args: any[]) => VNode[]
@ -125,14 +125,10 @@ export const updateSlots = (
if (vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
if ((children as RawSlots)._ === 1) {
// compiled slots.
if (__DEV__ && instance.parent && instance.parent.hmrUpdated) {
if (__DEV__ && isHmrUpdating) {
// Parent was HMR updated so slot content may have changed.
// force update slots and mark instance for hmr as well
extend(slots, children as Slots)
instance.hmrUpdated = true
queuePostFlushCb(() => {
instance.hmrUpdated = false
})
} else if (
// bail on dynamic slots (v-if, v-for, reference of scope variables)
!(vnode.patchFlag & PatchFlags.DYNAMIC_SLOTS)

View File

@ -1,5 +1,6 @@
/* eslint-disable no-restricted-globals */
import {
Component,
ComponentInternalInstance,
ComponentOptions,
InternalRenderFunction
@ -7,6 +8,10 @@ import {
import { queueJob, queuePostFlushCb } from './scheduler'
import { extend } from '@vue/shared'
export let isHmrUpdating = false
export const hmrDirtyComponents = new Set<Component>()
export interface HMRRuntime {
createRecord: typeof createRecord
rerender: typeof rerender
@ -72,9 +77,9 @@ function rerender(id: string, newRender?: Function) {
}
instance.renderCache = []
// this flag forces child components with slot content to update
instance.hmrUpdated = true
isHmrUpdating = true
instance.update()
instance.hmrUpdated = false
isHmrUpdating = false
})
}
@ -85,7 +90,7 @@ function reload(id: string, newComp: ComponentOptions) {
// updates
Array.from(record).forEach(instance => {
const comp = instance.type
if (!comp.__hmrUpdated) {
if (!hmrDirtyComponents.has(comp)) {
// 1. Update existing comp definition to match new one
extend(comp, newComp)
for (const key in comp) {
@ -95,10 +100,10 @@ function reload(id: string, newComp: ComponentOptions) {
}
// 2. Mark component dirty. This forces the renderer to replace the component
// on patch.
comp.__hmrUpdated = true
hmrDirtyComponents.add(comp)
// 3. Make sure to unmark the component after the reload.
queuePostFlushCb(() => {
comp.__hmrUpdated = false
hmrDirtyComponents.delete(comp)
})
}

View File

@ -56,7 +56,7 @@ import {
} from './components/Suspense'
import { TeleportImpl } from './components/Teleport'
import { isKeepAlive, KeepAliveContext } from './components/KeepAlive'
import { registerHMR, unregisterHMR } from './hmr'
import { registerHMR, unregisterHMR, isHmrUpdating } from './hmr'
import {
ErrorCodes,
callWithErrorHandling,
@ -791,18 +791,11 @@ function baseCreateRenderer(
invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate')
}
// check if any component of the parent chain has `hmrUpdated`
if (__DEV__ && parentComponent) {
let parent: ComponentInternalInstance | null = parentComponent
do {
if (parent.hmrUpdated) {
// HMR updated, force full diff
patchFlag = 0
optimized = false
dynamicChildren = null
break
}
} while ((parent = parent.parent))
if (__DEV__ && isHmrUpdating) {
// HMR updated, force full diff
patchFlag = 0
optimized = false
dynamicChildren = null
}
if (patchFlag > 0) {
@ -1025,7 +1018,7 @@ function baseCreateRenderer(
optimized = true
}
if (__DEV__ && parentComponent && parentComponent.hmrUpdated) {
if (__DEV__ && isHmrUpdating) {
// HMR updated, force full diff
patchFlag = 0
optimized = false

View File

@ -32,6 +32,7 @@ import { TeleportImpl, isTeleport } from './components/Teleport'
import { currentRenderingInstance } from './componentRenderUtils'
import { RendererNode, RendererElement } from './renderer'
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
import { hmrDirtyComponents } from './hmr'
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
__isFragment: true
@ -236,7 +237,7 @@ export function isSameVNodeType(n1: VNode, n2: VNode): boolean {
if (
__DEV__ &&
n2.shapeFlag & ShapeFlags.COMPONENT &&
(n2.type as Component).__hmrUpdated
hmrDirtyComponents.has(n2.type as Component)
) {
// HMR only: if the component has been hot-updated, force a reload.
return false