refactor(hmr): simplify hmr force update check
This commit is contained in:
parent
8f2a7489b7
commit
e76ed4c269
@ -71,10 +71,6 @@ export interface ComponentInternalOptions {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
__hmrId?: string
|
__hmrId?: string
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
__hmrUpdated?: boolean
|
|
||||||
/**
|
/**
|
||||||
* This one should be exposed so that devtools can make use of it
|
* This one should be exposed so that devtools can make use of it
|
||||||
*/
|
*/
|
||||||
@ -325,12 +321,6 @@ export interface ComponentInternalInstance {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
[LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
|
[LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
|
||||||
|
|
||||||
/**
|
|
||||||
* hmr marker (dev only)
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
hmrUpdated?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyAppContext = createAppContext()
|
const emptyAppContext = createAppContext()
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
import { handleError, ErrorCodes } from './errorHandling'
|
import { handleError, ErrorCodes } from './errorHandling'
|
||||||
import { PatchFlags, ShapeFlags, isOn } from '@vue/shared'
|
import { PatchFlags, ShapeFlags, isOn } from '@vue/shared'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
|
import { isHmrUpdating } from './hmr'
|
||||||
|
|
||||||
// mark the current rendering instance for asset resolution (e.g.
|
// mark the current rendering instance for asset resolution (e.g.
|
||||||
// resolveComponent, resolveDirective) during render
|
// resolveComponent, resolveDirective) during render
|
||||||
@ -247,13 +248,8 @@ export function shouldUpdateComponent(
|
|||||||
// Parent component's render function was hot-updated. Since this may have
|
// 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
|
// caused the child component's slots content to have changed, we need to
|
||||||
// force the child to update as well.
|
// force the child to update as well.
|
||||||
if (__DEV__ && (prevChildren || nextChildren) && parentComponent) {
|
if (__DEV__ && (prevChildren || nextChildren) && isHmrUpdating) {
|
||||||
let parent: ComponentInternalInstance | null = parentComponent
|
return true
|
||||||
do {
|
|
||||||
if (parent.hmrUpdated) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} while ((parent = parent.parent))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// force child update for runtime directive or transition on component vnode.
|
// force child update for runtime directive or transition on component vnode.
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import { isKeepAlive } from './components/KeepAlive'
|
import { isKeepAlive } from './components/KeepAlive'
|
||||||
import { withCtx } from './helpers/withRenderContext'
|
import { withCtx } from './helpers/withRenderContext'
|
||||||
import { queuePostFlushCb } from './scheduler'
|
import { isHmrUpdating } from './hmr'
|
||||||
|
|
||||||
export type Slot = (...args: any[]) => VNode[]
|
export type Slot = (...args: any[]) => VNode[]
|
||||||
|
|
||||||
@ -125,14 +125,10 @@ export const updateSlots = (
|
|||||||
if (vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
|
if (vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
|
||||||
if ((children as RawSlots)._ === 1) {
|
if ((children as RawSlots)._ === 1) {
|
||||||
// compiled slots.
|
// compiled slots.
|
||||||
if (__DEV__ && instance.parent && instance.parent.hmrUpdated) {
|
if (__DEV__ && isHmrUpdating) {
|
||||||
// Parent was HMR updated so slot content may have changed.
|
// Parent was HMR updated so slot content may have changed.
|
||||||
// force update slots and mark instance for hmr as well
|
// force update slots and mark instance for hmr as well
|
||||||
extend(slots, children as Slots)
|
extend(slots, children as Slots)
|
||||||
instance.hmrUpdated = true
|
|
||||||
queuePostFlushCb(() => {
|
|
||||||
instance.hmrUpdated = false
|
|
||||||
})
|
|
||||||
} else if (
|
} else if (
|
||||||
// bail on dynamic slots (v-if, v-for, reference of scope variables)
|
// bail on dynamic slots (v-if, v-for, reference of scope variables)
|
||||||
!(vnode.patchFlag & PatchFlags.DYNAMIC_SLOTS)
|
!(vnode.patchFlag & PatchFlags.DYNAMIC_SLOTS)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/* eslint-disable no-restricted-globals */
|
/* eslint-disable no-restricted-globals */
|
||||||
import {
|
import {
|
||||||
|
Component,
|
||||||
ComponentInternalInstance,
|
ComponentInternalInstance,
|
||||||
ComponentOptions,
|
ComponentOptions,
|
||||||
InternalRenderFunction
|
InternalRenderFunction
|
||||||
@ -7,6 +8,10 @@ import {
|
|||||||
import { queueJob, queuePostFlushCb } from './scheduler'
|
import { queueJob, queuePostFlushCb } from './scheduler'
|
||||||
import { extend } from '@vue/shared'
|
import { extend } from '@vue/shared'
|
||||||
|
|
||||||
|
export let isHmrUpdating = false
|
||||||
|
|
||||||
|
export const hmrDirtyComponents = new Set<Component>()
|
||||||
|
|
||||||
export interface HMRRuntime {
|
export interface HMRRuntime {
|
||||||
createRecord: typeof createRecord
|
createRecord: typeof createRecord
|
||||||
rerender: typeof rerender
|
rerender: typeof rerender
|
||||||
@ -72,9 +77,9 @@ function rerender(id: string, newRender?: Function) {
|
|||||||
}
|
}
|
||||||
instance.renderCache = []
|
instance.renderCache = []
|
||||||
// this flag forces child components with slot content to update
|
// this flag forces child components with slot content to update
|
||||||
instance.hmrUpdated = true
|
isHmrUpdating = true
|
||||||
instance.update()
|
instance.update()
|
||||||
instance.hmrUpdated = false
|
isHmrUpdating = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +90,7 @@ function reload(id: string, newComp: ComponentOptions) {
|
|||||||
// updates
|
// updates
|
||||||
Array.from(record).forEach(instance => {
|
Array.from(record).forEach(instance => {
|
||||||
const comp = instance.type
|
const comp = instance.type
|
||||||
if (!comp.__hmrUpdated) {
|
if (!hmrDirtyComponents.has(comp)) {
|
||||||
// 1. Update existing comp definition to match new one
|
// 1. Update existing comp definition to match new one
|
||||||
extend(comp, newComp)
|
extend(comp, newComp)
|
||||||
for (const key in comp) {
|
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
|
// 2. Mark component dirty. This forces the renderer to replace the component
|
||||||
// on patch.
|
// on patch.
|
||||||
comp.__hmrUpdated = true
|
hmrDirtyComponents.add(comp)
|
||||||
// 3. Make sure to unmark the component after the reload.
|
// 3. Make sure to unmark the component after the reload.
|
||||||
queuePostFlushCb(() => {
|
queuePostFlushCb(() => {
|
||||||
comp.__hmrUpdated = false
|
hmrDirtyComponents.delete(comp)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ import {
|
|||||||
} from './components/Suspense'
|
} from './components/Suspense'
|
||||||
import { TeleportImpl } from './components/Teleport'
|
import { TeleportImpl } from './components/Teleport'
|
||||||
import { isKeepAlive, KeepAliveContext } from './components/KeepAlive'
|
import { isKeepAlive, KeepAliveContext } from './components/KeepAlive'
|
||||||
import { registerHMR, unregisterHMR } from './hmr'
|
import { registerHMR, unregisterHMR, isHmrUpdating } from './hmr'
|
||||||
import {
|
import {
|
||||||
ErrorCodes,
|
ErrorCodes,
|
||||||
callWithErrorHandling,
|
callWithErrorHandling,
|
||||||
@ -791,18 +791,11 @@ function baseCreateRenderer(
|
|||||||
invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate')
|
invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate')
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if any component of the parent chain has `hmrUpdated`
|
if (__DEV__ && isHmrUpdating) {
|
||||||
if (__DEV__ && parentComponent) {
|
// HMR updated, force full diff
|
||||||
let parent: ComponentInternalInstance | null = parentComponent
|
patchFlag = 0
|
||||||
do {
|
optimized = false
|
||||||
if (parent.hmrUpdated) {
|
dynamicChildren = null
|
||||||
// HMR updated, force full diff
|
|
||||||
patchFlag = 0
|
|
||||||
optimized = false
|
|
||||||
dynamicChildren = null
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} while ((parent = parent.parent))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patchFlag > 0) {
|
if (patchFlag > 0) {
|
||||||
@ -1025,7 +1018,7 @@ function baseCreateRenderer(
|
|||||||
optimized = true
|
optimized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__DEV__ && parentComponent && parentComponent.hmrUpdated) {
|
if (__DEV__ && isHmrUpdating) {
|
||||||
// HMR updated, force full diff
|
// HMR updated, force full diff
|
||||||
patchFlag = 0
|
patchFlag = 0
|
||||||
optimized = false
|
optimized = false
|
||||||
|
@ -32,6 +32,7 @@ import { TeleportImpl, isTeleport } from './components/Teleport'
|
|||||||
import { currentRenderingInstance } from './componentRenderUtils'
|
import { currentRenderingInstance } from './componentRenderUtils'
|
||||||
import { RendererNode, RendererElement } from './renderer'
|
import { RendererNode, RendererElement } from './renderer'
|
||||||
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
|
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
|
||||||
|
import { hmrDirtyComponents } from './hmr'
|
||||||
|
|
||||||
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
|
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
|
||||||
__isFragment: true
|
__isFragment: true
|
||||||
@ -236,7 +237,7 @@ export function isSameVNodeType(n1: VNode, n2: VNode): boolean {
|
|||||||
if (
|
if (
|
||||||
__DEV__ &&
|
__DEV__ &&
|
||||||
n2.shapeFlag & ShapeFlags.COMPONENT &&
|
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.
|
// HMR only: if the component has been hot-updated, force a reload.
|
||||||
return false
|
return false
|
||||||
|
Loading…
Reference in New Issue
Block a user