diff --git a/packages/runtime-core/src/hmr.ts b/packages/runtime-core/src/hmr.ts index 4a37f4f87..0e2dfe750 100644 --- a/packages/runtime-core/src/hmr.ts +++ b/packages/runtime-core/src/hmr.ts @@ -33,10 +33,7 @@ if (__DEV__) { } as HMRRuntime } -interface HMRRecord { - comp: ComponentOptions - instances: Set -} +type HMRRecord = Set const map: Map = new Map() @@ -47,21 +44,18 @@ export function registerHMR(instance: ComponentInternalInstance) { createRecord(id, instance.type as ComponentOptions) record = map.get(id)! } - record.instances.add(instance) + record.add(instance) } export function unregisterHMR(instance: ComponentInternalInstance) { - map.get(instance.type.__hmrId!)!.instances.delete(instance) + map.get(instance.type.__hmrId!)!.delete(instance) } function createRecord(id: string, comp: ComponentOptions): boolean { if (map.has(id)) { return false } - map.set(id, { - comp, - instances: new Set() - }) + map.set(id, new Set()) return true } @@ -70,7 +64,7 @@ function rerender(id: string, newRender?: Function) { if (!record) return // Array.from creates a snapshot which avoids the set being mutated during // updates - Array.from(record.instances).forEach(instance => { + Array.from(record).forEach(instance => { if (newRender) { instance.render = newRender as InternalRenderFunction } @@ -85,22 +79,29 @@ function rerender(id: string, newRender?: Function) { function reload(id: string, newComp: ComponentOptions) { const record = map.get(id) if (!record) return - // 1. Update existing comp definition to match new one - const comp = record.comp - Object.assign(comp, newComp) - for (const key in comp) { - if (!(key in newComp)) { - delete (comp as any)[key] - } - } - // 2. Mark component dirty. This forces the renderer to replace the component - // on patch. - comp.__hmrUpdated = true // Array.from creates a snapshot which avoids the set being mutated during // updates - Array.from(record.instances).forEach(instance => { + Array.from(record).forEach(instance => { + const comp = instance.type + if (!comp.__hmrUpdated) { + // 1. Update existing comp definition to match new one + Object.assign(comp, newComp) + for (const key in comp) { + if (!(key in newComp)) { + delete (comp as any)[key] + } + } + // 2. Mark component dirty. This forces the renderer to replace the component + // on patch. + comp.__hmrUpdated = true + // 3. Make sure to unmark the component after the reload. + queuePostFlushCb(() => { + comp.__hmrUpdated = false + }) + } + if (instance.parent) { - // 3. Force the parent instance to re-render. This will cause all updated + // 4. Force the parent instance to re-render. This will cause all updated // components to be unmounted and re-mounted. Queue the update so that we // don't end up forcing the same parent to re-render multiple times. queueJob(instance.parent.update) @@ -116,10 +117,6 @@ function reload(id: string, newComp: ComponentOptions) { ) } }) - // 4. Make sure to unmark the component after the reload. - queuePostFlushCb(() => { - comp.__hmrUpdated = false - }) } function tryWrap(fn: (id: string, arg: any) => any): Function {